From a86ff9dfd145231c0a12bda9d6a478f6397ef239 Mon Sep 17 00:00:00 2001 From: ma wei Date: Tue, 2 Jun 2015 14:03:03 +0800 Subject: [PATCH 01/41] Add ability for user to configure CVE url in gradle build file Former-commit-id: 186b03ff55c9cab1c7bd788e5ea5ba1f8e79241e --- .../DependencyCheckConfigurationExtension.groovy | 6 ++++++ .../com/tools/security/tasks/DependencyCheckTask.groovy | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/dependency-check-gradle/src/main/groovy/com/tools/security/extension/DependencyCheckConfigurationExtension.groovy b/dependency-check-gradle/src/main/groovy/com/tools/security/extension/DependencyCheckConfigurationExtension.groovy index 53659cbbe..0a9f220fb 100644 --- a/dependency-check-gradle/src/main/groovy/com/tools/security/extension/DependencyCheckConfigurationExtension.groovy +++ b/dependency-check-gradle/src/main/groovy/com/tools/security/extension/DependencyCheckConfigurationExtension.groovy @@ -23,4 +23,10 @@ class DependencyCheckConfigurationExtension { Integer proxyPort String proxyUsername = "" String proxyPassword = "" + + String cveUrl12Modified = "https://nvd.nist.gov/download/nvdcve-Modified.xml.gz" + String cveUrl20Modified = "https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz" + Integer cveStartYear = 2002 + String cveUrl12Base = "https://nvd.nist.gov/download/nvdcve-%d.xml.gz" + String cveUrl20Base = "https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz" } diff --git a/dependency-check-gradle/src/main/groovy/com/tools/security/tasks/DependencyCheckTask.groovy b/dependency-check-gradle/src/main/groovy/com/tools/security/tasks/DependencyCheckTask.groovy index f5d582194..6413a89fe 100644 --- a/dependency-check-gradle/src/main/groovy/com/tools/security/tasks/DependencyCheckTask.groovy +++ b/dependency-check-gradle/src/main/groovy/com/tools/security/tasks/DependencyCheckTask.groovy @@ -52,6 +52,7 @@ class DependencyCheckTask extends DefaultTask { def initializeSettings() { Settings.initialize() overrideProxySetting() + overrideCveUrlSetting() } def verifyDependencies(engine) { @@ -101,4 +102,12 @@ class DependencyCheckTask extends DefaultTask { } }.flatten(); } + + def overrideCveUrlSetting() { + setString(Settings.KEYS.CVE_MODIFIED_20_URL, project.dependencyCheck.cveUrl20Modified) + setString(Settings.KEYS.CVE_MODIFIED_12_URL, project.dependencyCheck.cveUrl12Modified) + setString(Settings.KEYS.CVE_START_YEAR, "${project.dependencyCheck.cveStartYear}") + setString(Settings.KEYS.CVE_SCHEMA_2_0, project.dependencyCheck.cveUrl20Base) + setString(Settings.KEYS.CVE_SCHEMA_1_2, project.dependencyCheck.cveUrl12Base) + } } From 6e281e0b66a4fe136c9ffc2ce149c777d7c9f403 Mon Sep 17 00:00:00 2001 From: ma wei Date: Tue, 2 Jun 2015 14:14:06 +0800 Subject: [PATCH 02/41] Add gradle task to publish this plugin to Maven Central Former-commit-id: dc5bfcbc382d7eb5f227c655214560082c8b9633 --- dependency-check-gradle/build.gradle | 64 +++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/dependency-check-gradle/build.gradle b/dependency-check-gradle/build.gradle index 416626d8d..8efc63090 100644 --- a/dependency-check-gradle/build.gradle +++ b/dependency-check-gradle/build.gradle @@ -35,6 +35,7 @@ plugins { apply plugin: 'idea' apply plugin: 'groovy' apply plugin: 'maven' +apply plugin: 'signing' apply plugin: "com.gradle.plugin-publish" repositories { @@ -56,14 +57,73 @@ version = '0.0.3' //------------------------------- // Local debug use only // +//uploadArchives { +// repositories { +// mavenDeployer { +// repository(url: uri('../../../repo')) +// } +// } +//} +//------------------------------- + + +// upload to maven central uploadArchives { repositories { mavenDeployer { - repository(url: uri('../../../repo')) + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: sonatypeUsername, password: sonatypePassword) + } + + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication(userName: sonatypeUsername, password: sonatypePassword) + } + + pom.project { + name 'Dependency Check Gradle Plugin' + packaging 'jar' + description 'Dependency-Check is a utility that attempts to detect publicly disclosed vulnerabilities contained within project dependencies.' + url 'https://github.com/wmaintw/DependencyCheck/tree/master/dependency-check-gradle' + + scm { + connection 'git@github.com:wmaintw/DependencyCheck.git' + developerConnection 'git@github.com:wmaintw/DependencyCheck.git' + url 'https://github.com/wmaintw/DependencyCheck' + } + + licenses { + license { + name 'The Apache License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + + developers { + developer { + id 'wmaintw' + name 'Wei Ma' + email 'wma@thoughtworks.com' + } + } + } } } } -//------------------------------- + +task javadocJar(type: Jar) { + classifier = 'javadoc' + from javadoc +} + +artifacts { + archives javadocJar, sourcesJar +} + +signing { + sign configurations.archives +} // publish to Bintray plugindev { From 4e41187bf310011e2017255f490bc2881bee8ebb Mon Sep 17 00:00:00 2001 From: ma wei Date: Sat, 6 Jun 2015 10:28:52 +0800 Subject: [PATCH 03/41] Modify version to 0.0.4, changed the GroupId in order to release to MavenCentral Former-commit-id: 7f57d17742215afcf3a9e2b4aa82e93d7444439e --- dependency-check-gradle/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependency-check-gradle/build.gradle b/dependency-check-gradle/build.gradle index 8efc63090..d756ae679 100644 --- a/dependency-check-gradle/build.gradle +++ b/dependency-check-gradle/build.gradle @@ -51,8 +51,8 @@ dependencies { ) } -group = 'com.tools.security' -version = '0.0.3' +group = 'com.thoughtworks.tools' +version = '0.0.4' //------------------------------- // Local debug use only From 5e66f70cf0bee94ee886970ee1cda2b86ab7b93e Mon Sep 17 00:00:00 2001 From: ma wei Date: Sat, 6 Jun 2015 10:29:50 +0800 Subject: [PATCH 04/41] Update README, add usage for install plugin from MavenCentral Former-commit-id: 26c9119b6eeb042e46f9855a2c51c48a0675419b --- dependency-check-gradle/README.md | 181 ++++++++++++++---------------- 1 file changed, 85 insertions(+), 96 deletions(-) diff --git a/dependency-check-gradle/README.md b/dependency-check-gradle/README.md index a7f10a66d..f8734466c 100644 --- a/dependency-check-gradle/README.md +++ b/dependency-check-gradle/README.md @@ -15,7 +15,49 @@ Dependency-Check is a utility that attempts to detect publicly disclosed vulnera Please refer to either one of the solution -#### Solution 1,Bintray +#### Solution 1,Install from Maven Central + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.thoughtworks.tools:dependency-check:0.0.4' + } +} + +apply plugin: 'dependency.check' + +#### Solution 2,Install from Gradle Plugin Portal + +[dependency check gradle plugin on Gradle Plugin Portal](https://plugins.gradle.org/plugin/dependency.check) + +**Build script snippet for new, incubating, plugin mechanism introduced in Gradle 2.1:** + +``` +plugins { + id "dependency.check" version "0.0.4" +} +``` + +**Build script snippet for use in all Gradle versions:** + +``` +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "gradle.plugin.com.tools.security:dependency-check:0.0.4" + } +} + +apply plugin: "dependency.check" +``` + +#### Solution 3,Install from Bintray ``` apply plugin: "dependency-check" @@ -29,105 +71,12 @@ buildscript { } dependencies { classpath( - 'com.tools.security:dependency-check:0.0.3' + 'com.tools.security:dependency-check:0.0.4' ) } } ``` -#### Solution 2,Gradle Plugin Portal - -[dependency check gradle plugin on Gradle Plugin Portal](https://plugins.gradle.org/plugin/dependency.check) - -**Build script snippet for new, incubating, plugin mechanism introduced in Gradle 2.1:** - -``` -// buildscript { -// ... -// } - -plugins { - id "dependency.check" version "0.0.3" -} - -// apply plugin: ... -``` - -**Build script snippet for use in all Gradle versions:** - -``` -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "gradle.plugin.com.tools.security:dependency-check:0.0.3" - } -} - -apply plugin: "dependency.check" -``` - -**If your project includes multiple sub-project, configure build script this way:** - -``` -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "gradle.plugin.com.tools.security:dependency-check:0.0.3" - } -} - -allprojects { - //other plugins you may use - //apply plugin: "java" - - apply plugin: "dependency-check" - - repositories { - mavenCentral() - } -} -``` - -or - -``` -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "gradle.plugin.com.tools.security:dependency-check:0.0.3" - } -} - -subprojects { - //other plugins you may use - //apply plugin: "java" - - apply plugin: "dependency-check" - - repositories { - mavenCentral() - } -} -``` - -In this way, the dependency check will be executed for all projects (including root project) or just sub projects. - -#### Solution 3,Maven Central - -working in progress - ### Step 2, Run gradle task Once gradle plugin applied, run following gradle task to check the dependencies: @@ -140,7 +89,9 @@ The reports will be generated automatically under `./reports` folder. If your project includes multiple sub-projects, the report will be generated for each sub-project in different sub-directory. -### What if you are behind a proxy? +### FAQ + +## What if I'm behind a proxy? Maybe you have to use proxy to access internet, in this case, you could configure proxy settings for this plugin: @@ -156,3 +107,41 @@ dependencyCheck { // proxyPassword = "password" } ``` + +## What if my project includes multiple sub-project? How can I use this plugin for each of them including the root project?** + +Try put 'apply plugin: "dependency-check"' inside the 'allprojects' or 'subprojects' if you'd like to check all sub-projects only, see below: + +(1) For all projects including root project: +``` +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath "gradle.plugin.com.tools.security:dependency-check:0.0.4" + } +} + +allprojects { + apply plugin: "dependency-check" +} +``` + +(2) For all sub-projects: +``` +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath "gradle.plugin.com.tools.security:dependency-check:0.0.4" + } +} + +subprojects { + apply plugin: "dependency-check" +} +``` + +In this way, the dependency check will be executed for all projects (including root project) or just sub projects. \ No newline at end of file From 28c2db9edc47f62a2f9ee5ae68a3c30962934267 Mon Sep 17 00:00:00 2001 From: ma wei Date: Sat, 6 Jun 2015 10:32:02 +0800 Subject: [PATCH 05/41] adjust format in README Former-commit-id: 6a905bf23bec0f939974d83d53941a54d0dd851a --- dependency-check-gradle/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dependency-check-gradle/README.md b/dependency-check-gradle/README.md index f8734466c..f3b322e90 100644 --- a/dependency-check-gradle/README.md +++ b/dependency-check-gradle/README.md @@ -17,6 +17,7 @@ Please refer to either one of the solution #### Solution 1,Install from Maven Central +```groovy buildscript { repositories { mavenCentral() @@ -25,6 +26,7 @@ buildscript { classpath 'com.thoughtworks.tools:dependency-check:0.0.4' } } +``` apply plugin: 'dependency.check' @@ -89,9 +91,9 @@ The reports will be generated automatically under `./reports` folder. If your project includes multiple sub-projects, the report will be generated for each sub-project in different sub-directory. -### FAQ +## FAQ -## What if I'm behind a proxy? +### What if I'm behind a proxy? Maybe you have to use proxy to access internet, in this case, you could configure proxy settings for this plugin: @@ -108,7 +110,7 @@ dependencyCheck { } ``` -## What if my project includes multiple sub-project? How can I use this plugin for each of them including the root project?** +### What if my project includes multiple sub-project? How can I use this plugin for each of them including the root project?** Try put 'apply plugin: "dependency-check"' inside the 'allprojects' or 'subprojects' if you'd like to check all sub-projects only, see below: From 80276d5e4dbf59bd2641b7127d45757b56109383 Mon Sep 17 00:00:00 2001 From: ma wei Date: Sat, 6 Jun 2015 10:33:43 +0800 Subject: [PATCH 06/41] adjust format in README Former-commit-id: 7bcc077020394df43130bcd35d60cf1063b6c815 --- dependency-check-gradle/README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/dependency-check-gradle/README.md b/dependency-check-gradle/README.md index f3b322e90..19af23fcd 100644 --- a/dependency-check-gradle/README.md +++ b/dependency-check-gradle/README.md @@ -36,7 +36,7 @@ apply plugin: 'dependency.check' **Build script snippet for new, incubating, plugin mechanism introduced in Gradle 2.1:** -``` +```groovy plugins { id "dependency.check" version "0.0.4" } @@ -44,7 +44,7 @@ plugins { **Build script snippet for use in all Gradle versions:** -``` +```groovy buildscript { repositories { maven { @@ -61,7 +61,7 @@ apply plugin: "dependency.check" #### Solution 3,Install from Bintray -``` +```groovy apply plugin: "dependency-check" buildscript { @@ -97,7 +97,7 @@ If your project includes multiple sub-projects, the report will be generated for Maybe you have to use proxy to access internet, in this case, you could configure proxy settings for this plugin: -``` +```groovy dependencyCheck { proxyServer = "127.0.0.1" // required, the server name or IP address of the proxy proxyPort = 3128 // required, the port number of the proxy @@ -110,12 +110,13 @@ dependencyCheck { } ``` -### What if my project includes multiple sub-project? How can I use this plugin for each of them including the root project?** +### What if my project includes multiple sub-project? How can I use this plugin for each of them including the root project? Try put 'apply plugin: "dependency-check"' inside the 'allprojects' or 'subprojects' if you'd like to check all sub-projects only, see below: (1) For all projects including root project: -``` + +```groovy buildscript { repositories { mavenCentral() @@ -131,7 +132,8 @@ allprojects { ``` (2) For all sub-projects: -``` + +```groovy buildscript { repositories { mavenCentral() From aa927e9168dc1bcca25bf17361162574af2420d2 Mon Sep 17 00:00:00 2001 From: ma wei Date: Thu, 11 Jun 2015 10:11:07 +0800 Subject: [PATCH 07/41] refactor the build.gradle file, extract publish tasks to separated gradle file Former-commit-id: 539b8d16917a8a60e07a7f1466ce9ad0c84ca94e --- dependency-check-gradle/build.gradle | 113 +----------------- .../conf/publish/bintray.gradle | 23 ++++ .../conf/publish/gradlePluginsPortal.gradle | 14 +++ .../conf/publish/local.gradle | 8 ++ .../conf/publish/maven.gradle | 57 +++++++++ 5 files changed, 106 insertions(+), 109 deletions(-) create mode 100644 dependency-check-gradle/conf/publish/bintray.gradle create mode 100644 dependency-check-gradle/conf/publish/gradlePluginsPortal.gradle create mode 100644 dependency-check-gradle/conf/publish/local.gradle create mode 100644 dependency-check-gradle/conf/publish/maven.gradle diff --git a/dependency-check-gradle/build.gradle b/dependency-check-gradle/build.gradle index d756ae679..9176ae9b8 100644 --- a/dependency-check-gradle/build.gradle +++ b/dependency-check-gradle/build.gradle @@ -54,112 +54,7 @@ dependencies { group = 'com.thoughtworks.tools' version = '0.0.4' -//------------------------------- -// Local debug use only -// -//uploadArchives { -// repositories { -// mavenDeployer { -// repository(url: uri('../../../repo')) -// } -// } -//} -//------------------------------- - - -// upload to maven central -uploadArchives { - repositories { - mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - - repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { - authentication(userName: sonatypeUsername, password: sonatypePassword) - } - - snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { - authentication(userName: sonatypeUsername, password: sonatypePassword) - } - - pom.project { - name 'Dependency Check Gradle Plugin' - packaging 'jar' - description 'Dependency-Check is a utility that attempts to detect publicly disclosed vulnerabilities contained within project dependencies.' - url 'https://github.com/wmaintw/DependencyCheck/tree/master/dependency-check-gradle' - - scm { - connection 'git@github.com:wmaintw/DependencyCheck.git' - developerConnection 'git@github.com:wmaintw/DependencyCheck.git' - url 'https://github.com/wmaintw/DependencyCheck' - } - - licenses { - license { - name 'The Apache License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - - developers { - developer { - id 'wmaintw' - name 'Wei Ma' - email 'wma@thoughtworks.com' - } - } - } - } - } -} - -task javadocJar(type: Jar) { - classifier = 'javadoc' - from javadoc -} - -artifacts { - archives javadocJar, sourcesJar -} - -signing { - sign configurations.archives -} - -// publish to Bintray -plugindev { - pluginId = 'dependency.check' - pluginName = 'dependency-check' - pluginImplementationClass 'com.tools.security.plugin.DependencyCheckGradlePlugin' - pluginDescription 'This is dependency check gradle plugin.' - pluginLicenses 'Apache-2.0' - pluginTags 'dependency check', 'security' - authorId 'wmaintw' - authorName 'Wei Ma' - authorEmail 'wma@thoughtworks.com' - projectUrl 'https://github.com/wmaintw/DependencyCheck' - projectIssuesUrl 'https://github.com/wmaintw/DependencyCheck/issues' - projectVcsUrl 'git@github.com:wmaintw/DependencyCheck.git' - projectInceptionYear '2015' - done() -} - -bintray { - user = bintrayUser - key = bintrayUserKey - pkg.repo = bintrayRepo -} - -// publish to gradle plugin portal -pluginBundle { - website = 'https://github.com/wmaintw/DependencyCheck' - vcsUrl = 'git@github.com:wmaintw/DependencyCheck.git' - description = 'This is dependency check gradle plugin.' - tags = ['dependency check', 'security'] - - plugins { - dependencyCheckPlugin { - id = 'dependency.check' - displayName = 'dependency-check' - } - } -} \ No newline at end of file +apply from: 'conf/publish/local.gradle' +//apply from: 'conf/publish/maven.gradle' +apply from: 'conf/publish/gradlePluginsPortal.gradle' +apply from: 'conf/publish/bintray.gradle' // according to the documentation of plugindev, this line has to be placed and the very end of the build file \ No newline at end of file diff --git a/dependency-check-gradle/conf/publish/bintray.gradle b/dependency-check-gradle/conf/publish/bintray.gradle new file mode 100644 index 000000000..ba8f0ad6a --- /dev/null +++ b/dependency-check-gradle/conf/publish/bintray.gradle @@ -0,0 +1,23 @@ +// publish to Bintray +plugindev { + pluginId = 'dependency.check' + pluginName = 'dependency-check' + pluginImplementationClass 'com.tools.security.plugin.DependencyCheckGradlePlugin' + pluginDescription 'This is dependency check gradle plugin.' + pluginLicenses 'Apache-2.0' + pluginTags 'dependency check', 'security' + authorId 'wmaintw' + authorName 'Wei Ma' + authorEmail 'wma@thoughtworks.com' + projectUrl 'https://github.com/wmaintw/DependencyCheck' + projectIssuesUrl 'https://github.com/wmaintw/DependencyCheck/issues' + projectVcsUrl 'git@github.com:wmaintw/DependencyCheck.git' + projectInceptionYear '2015' + done() +} + +bintray { + user = bintrayUser + key = bintrayUserKey + pkg.repo = bintrayRepo +} \ No newline at end of file diff --git a/dependency-check-gradle/conf/publish/gradlePluginsPortal.gradle b/dependency-check-gradle/conf/publish/gradlePluginsPortal.gradle new file mode 100644 index 000000000..198ca9a76 --- /dev/null +++ b/dependency-check-gradle/conf/publish/gradlePluginsPortal.gradle @@ -0,0 +1,14 @@ +// publish to gradle plugin portal +pluginBundle { + website = 'https://github.com/wmaintw/DependencyCheck' + vcsUrl = 'git@github.com:wmaintw/DependencyCheck.git' + description = 'This is dependency check gradle plugin.' + tags = ['dependency check', 'security'] + + plugins { + dependencyCheckPlugin { + id = 'dependency.check' + displayName = 'dependency-check' + } + } +} \ No newline at end of file diff --git a/dependency-check-gradle/conf/publish/local.gradle b/dependency-check-gradle/conf/publish/local.gradle new file mode 100644 index 000000000..e9b2f9d9a --- /dev/null +++ b/dependency-check-gradle/conf/publish/local.gradle @@ -0,0 +1,8 @@ +//Local debug use only +uploadArchives { + repositories { + mavenDeployer { + repository(url: uri('../../../repo')) + } + } +} \ No newline at end of file diff --git a/dependency-check-gradle/conf/publish/maven.gradle b/dependency-check-gradle/conf/publish/maven.gradle new file mode 100644 index 000000000..ea83a7c5e --- /dev/null +++ b/dependency-check-gradle/conf/publish/maven.gradle @@ -0,0 +1,57 @@ +//upload to maven central +uploadArchives { + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: sonatypeUsername, password: sonatypePassword) + } + + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication(userName: sonatypeUsername, password: sonatypePassword) + } + + pom.project { + name 'Dependency Check Gradle Plugin' + packaging 'jar' + description 'Dependency-Check is a utility that attempts to detect publicly disclosed vulnerabilities contained within project dependencies.' + url 'https://github.com/wmaintw/DependencyCheck/tree/master/dependency-check-gradle' + + scm { + connection 'git@github.com:wmaintw/DependencyCheck.git' + developerConnection 'git@github.com:wmaintw/DependencyCheck.git' + url 'https://github.com/wmaintw/DependencyCheck' + } + + licenses { + license { + name 'The Apache License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + + developers { + developer { + id 'wmaintw' + name 'Wei Ma' + email 'wma@thoughtworks.com' + } + } + } + } + } +} + +task javadocJar(type: Jar) { + classifier = 'javadoc' + from javadoc +} + +artifacts { + archives javadocJar, sourcesJar +} + +signing { + sign configurations.archives +} \ No newline at end of file From c713bb03538747982c7143fcf167da8f84df2751 Mon Sep 17 00:00:00 2001 From: Hans Joachim Desserud Date: Sun, 14 Jun 2015 17:45:18 +0200 Subject: [PATCH 08/41] Move reporting plugin version numbers into properties Former-commit-id: a3cbc3ba8647dc2118e6c35f2819c87eb2f98e6f --- dependency-check-utils/pom.xml | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/dependency-check-utils/pom.xml b/dependency-check-utils/pom.xml index 9dd12c78c..01881551f 100644 --- a/dependency-check-utils/pom.xml +++ b/dependency-check-utils/pom.xml @@ -39,6 +39,15 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved. UTF-8 + 2.5.3 + 2.11 + 2.6 + 2.9.1 + 2.4 + 3.0.1 + 2.16 + 2.4 + 2.1 @@ -104,7 +113,7 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + ${reporting.javadoc-plugin.version} false Copyright© 2012-15 Jeremy Long. All Rights Reserved. @@ -121,7 +130,7 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved. org.codehaus.mojo versions-maven-plugin - 2.1 + ${reporting.versions-plugin.version} @@ -134,17 +143,17 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-jxr-plugin - 2.4 + ${reporting.jxr-plugin.version} org.codehaus.mojo cobertura-maven-plugin - 2.6 + ${reporting.cobertura-plugin.version} org.apache.maven.plugins maven-surefire-report-plugin - 2.16 + ${reporting.surefire-report-plugin.version} @@ -156,7 +165,7 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved. org.codehaus.mojo taglist-maven-plugin - 2.4 + ${reporting.taglist-plugin.version} @@ -180,7 +189,7 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-checkstyle-plugin - 2.11 + ${reporting.checkstyle-plugin.version} false false @@ -193,7 +202,7 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-pmd-plugin - 3.0.1 + ${reporting.pmd-plugin.version} 1.6 true @@ -212,7 +221,7 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved. org.codehaus.mojo findbugs-maven-plugin - 2.5.3 + ${reporting.findbugs-plugin.version} org.owasp.dependencycheck.utils.* From ebd98b90949737c90aed54e277352e33f11a97a9 Mon Sep 17 00:00:00 2001 From: Hans Joachim Desserud Date: Sun, 21 Jun 2015 14:01:31 +0200 Subject: [PATCH 09/41] Move reporting-plugin-version properties to root pom Former-commit-id: eeff5c2d0f0fce884c3c12b071d030e4f0107302 --- dependency-check-utils/pom.xml | 9 --------- pom.xml | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dependency-check-utils/pom.xml b/dependency-check-utils/pom.xml index 01881551f..f80e2e7c3 100644 --- a/dependency-check-utils/pom.xml +++ b/dependency-check-utils/pom.xml @@ -39,15 +39,6 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved. UTF-8 - 2.5.3 - 2.11 - 2.6 - 2.9.1 - 2.4 - 3.0.1 - 2.16 - 2.4 - 2.1 diff --git a/pom.xml b/pom.xml index c1f21d987..69f64c921 100644 --- a/pom.xml +++ b/pom.xml @@ -129,6 +129,15 @@ Copyright (c) 2012 - Jeremy Long 4.7.2 1.7.12 1.1.3 + 2.11 + 2.6 + 2.5.3 + 2.9.1 + 2.4 + 3.0.1 + 2.16 + 2.4 + 2.1 From 358ac463930d1daf344549e7e4e51a60cf8fbad7 Mon Sep 17 00:00:00 2001 From: Hans Joachim Desserud Date: Sun, 21 Jun 2015 14:18:40 +0200 Subject: [PATCH 10/41] Replace reporting plugin version numbers with properties in core module Former-commit-id: dbd8588f6f259e03203700ebc2075fb8b84ff575 --- dependency-check-core/pom.xml | 20 ++++++++++---------- pom.xml | 2 ++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/dependency-check-core/pom.xml b/dependency-check-core/pom.xml index a1cf447ee..c38321a85 100644 --- a/dependency-check-core/pom.xml +++ b/dependency-check-core/pom.xml @@ -226,7 +226,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-project-info-reports-plugin - 2.7 + ${reporting.project-info-reports-plugin.version} @@ -240,7 +240,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + ${reporting.javadoc-plugin.version} false Copyright© 2012-15 Jeremy Long. All Rights Reserved. @@ -257,7 +257,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.codehaus.mojo versions-maven-plugin - 2.1 + ${reporting.versions-plugin.version} @@ -270,17 +270,17 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-jxr-plugin - 2.4 + ${reporting.jxr-plugin.version} org.codehaus.mojo cobertura-maven-plugin - 2.6 + ${reporting.cobertura-plugin.version} org.apache.maven.plugins maven-surefire-report-plugin - 2.16 + ${reporting.surefire-report-plugin.version} @@ -299,7 +299,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.codehaus.mojo taglist-maven-plugin - 2.4 + ${reporting.taglist-plugin.version} @@ -323,7 +323,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-checkstyle-plugin - 2.11 + ${reporting.checkstyle-plugin.version} false false @@ -336,7 +336,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-pmd-plugin - 3.1 + ${reporting.pmd-plugin.version} 1.6 true @@ -355,7 +355,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.codehaus.mojo findbugs-maven-plugin - 2.5.3 + ${reporting.findbugs-plugin.version} diff --git a/pom.xml b/pom.xml index 69f64c921..2dae9aeff 100644 --- a/pom.xml +++ b/pom.xml @@ -135,6 +135,8 @@ Copyright (c) 2012 - Jeremy Long 2.9.1 2.4 3.0.1 + + 2.7 2.16 2.4 2.1 From f421f3012299ac5bff2d1c6e052172c8c754893c Mon Sep 17 00:00:00 2001 From: Hans Joachim Desserud Date: Sun, 21 Jun 2015 14:38:41 +0200 Subject: [PATCH 11/41] Add (and sync) reporting plugins for jenkins module Former-commit-id: 0148cb4c9576f800f684299141e2e97b7d493bdd --- dependency-check-jenkins/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency-check-jenkins/pom.xml b/dependency-check-jenkins/pom.xml index 2671eab44..112975051 100644 --- a/dependency-check-jenkins/pom.xml +++ b/dependency-check-jenkins/pom.xml @@ -76,7 +76,7 @@ org.apache.maven.plugins maven-project-info-reports-plugin - 2.6 + ${reporting.project-info-reports-plugin.version} From b0df41213a7ae2f593a45b66de6420029f153812 Mon Sep 17 00:00:00 2001 From: Hans Joachim Desserud Date: Sun, 21 Jun 2015 14:42:15 +0200 Subject: [PATCH 12/41] Use properties in reporting version numbers in root pom Former-commit-id: 77b71beee1caeaa94712a8e3392952ea4bc78689 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2dae9aeff..a66a1285a 100644 --- a/pom.xml +++ b/pom.xml @@ -341,7 +341,7 @@ Copyright (c) 2012 - Jeremy Long org.apache.maven.plugins maven-project-info-reports-plugin - 2.7 + ${reporting.project-info-reports-plugin.version} From 0b2059462becb3918a3603c280ea848bb6581096 Mon Sep 17 00:00:00 2001 From: Hans Joachim Desserud Date: Sun, 21 Jun 2015 17:31:42 +0200 Subject: [PATCH 13/41] Replaced version numbers for reporting plugins in ant module Former-commit-id: 6eaa38d2988142c07b92e94933564d652b7852d3 --- dependency-check-ant/pom.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dependency-check-ant/pom.xml b/dependency-check-ant/pom.xml index dc10e0231..a18b4c19a 100644 --- a/dependency-check-ant/pom.xml +++ b/dependency-check-ant/pom.xml @@ -276,7 +276,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-project-info-reports-plugin - 2.7 + ${reporting.project-info-reports-plugin.version} @@ -290,7 +290,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + ${reporting.javadoc-plugin.version} false Copyright© 2012-15 Jeremy Long. All Rights Reserved. @@ -307,7 +307,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. org.codehaus.mojo versions-maven-plugin - 2.1 + ${reporting.versions-plugin.version} @@ -320,17 +320,17 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-jxr-plugin - 2.4 + ${reporting.jxr-plugin.version} org.codehaus.mojo cobertura-maven-plugin - 2.6 + ${reporting.cobertura-plugin.version} org.apache.maven.plugins maven-surefire-report-plugin - 2.16 + ${reporting.surefire-report-plugin.version} @@ -342,7 +342,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. org.codehaus.mojo taglist-maven-plugin - 2.4 + ${reporting.taglist-plugin.version} @@ -366,7 +366,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-checkstyle-plugin - 2.11 + ${reporting.checkstyle-plugin.version} false false @@ -379,7 +379,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-pmd-plugin - 3.0.1 + ${reporting.pmd-plugin.version} 1.6 true @@ -398,7 +398,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. org.codehaus.mojo findbugs-maven-plugin - 2.5.3 + ${reporting.findbugs-plugin.version} From 8fd32ebd5e39b9329bce3bc42f24ae5e7f873883 Mon Sep 17 00:00:00 2001 From: Hans Joachim Desserud Date: Sun, 21 Jun 2015 17:42:13 +0200 Subject: [PATCH 14/41] Replaced version numbers for reporting plugins in cli module Former-commit-id: c686c6f452ff1c514924d3c7dee59eaac4463af1 --- dependency-check-cli/pom.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dependency-check-cli/pom.xml b/dependency-check-cli/pom.xml index 8758bd827..ae36fd738 100644 --- a/dependency-check-cli/pom.xml +++ b/dependency-check-cli/pom.xml @@ -181,7 +181,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-project-info-reports-plugin - 2.7 + ${reporting.project-info-reports-plugin.version} @@ -195,7 +195,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + ${reporting.javadoc-plugin.version} false Copyright© 2012-15 Jeremy Long. All Rights Reserved. @@ -212,7 +212,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. org.codehaus.mojo versions-maven-plugin - 2.1 + ${reporting.versions-plugin.version} @@ -225,17 +225,17 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-jxr-plugin - 2.4 + ${reporting.jxr-plugin.version} org.codehaus.mojo cobertura-maven-plugin - 2.6 + ${reporting.cobertura-plugin.version} org.apache.maven.plugins maven-surefire-report-plugin - 2.16 + ${reporting.surefire-report-plugin.version} @@ -247,7 +247,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. org.codehaus.mojo taglist-maven-plugin - 2.4 + ${reporting.taglist-plugin.version} @@ -271,7 +271,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-checkstyle-plugin - 2.11 + ${reporting.checkstyle-plugin.version} false false @@ -284,7 +284,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-pmd-plugin - 3.1 + ${reporting.pmd-plugin.version} 1.6 true @@ -303,7 +303,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. org.codehaus.mojo findbugs-maven-plugin - 2.5.3 + ${reporting.findbugs-plugin.version} From 4f43793e174e66415cd658b0e671bfb56a347e73 Mon Sep 17 00:00:00 2001 From: Hans Joachim Desserud Date: Sun, 21 Jun 2015 17:43:04 +0200 Subject: [PATCH 15/41] Bonus: fixed copyright symbol Former-commit-id: 49d9f8af2055135238aa656cb69e20089a22e9fe --- dependency-check-cli/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency-check-cli/pom.xml b/dependency-check-cli/pom.xml index ae36fd738..2fa1b66c9 100644 --- a/dependency-check-cli/pom.xml +++ b/dependency-check-cli/pom.xml @@ -198,7 +198,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. ${reporting.javadoc-plugin.version} false - Copyright© 2012-15 Jeremy Long. All Rights Reserved. + Copyright© 2012-15 Jeremy Long. All Rights Reserved. From c1ae4f8cc2f39ca401b10c806cb30582ee309384 Mon Sep 17 00:00:00 2001 From: Hans Joachim Desserud Date: Sun, 21 Jun 2015 17:52:48 +0200 Subject: [PATCH 16/41] Replaced version numbers for reporting plugins in maven module Former-commit-id: e7ec67e0692d4233a2d6d651f50b0cd250c4587b --- dependency-check-maven/pom.xml | 22 +++++++++++----------- pom.xml | 4 +++- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/dependency-check-maven/pom.xml b/dependency-check-maven/pom.xml index 7e93fef11..ea50f8cf3 100644 --- a/dependency-check-maven/pom.xml +++ b/dependency-check-maven/pom.xml @@ -130,7 +130,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-project-info-reports-plugin - 2.7 + ${reporting.project-info-reports-plugin.version} @@ -144,7 +144,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-plugin-plugin - 3.2 + ${reporting.maven-plugin-plugin.version} dependency-check @@ -152,7 +152,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + ${reporting.javadoc-plugin.version} false Copyright© 2012-15 Jeremy Long. All Rights Reserved. @@ -169,7 +169,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. org.codehaus.mojo versions-maven-plugin - 2.1 + ${reporting.versions-plugin.version} @@ -182,17 +182,17 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-jxr-plugin - 2.4 + ${reporting.jxr-plugin.version} org.codehaus.mojo cobertura-maven-plugin - 2.6 + ${reporting.cobertura-plugin.version} org.apache.maven.plugins maven-surefire-report-plugin - 2.16 + ${reporting.surefire-report-plugin.version} @@ -204,7 +204,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. org.codehaus.mojo taglist-maven-plugin - 2.4 + ${reporting.taglist-plugin.version} @@ -228,7 +228,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-checkstyle-plugin - 2.11 + ${reporting.checkstyle-plugin.version} false false @@ -241,7 +241,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-pmd-plugin - 3.1 + ${reporting.pmd-plugin.version} 1.6 true @@ -261,7 +261,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. org.codehaus.mojo findbugs-maven-plugin - 2.5.3 + ${reporting.findbugs-plugin.version} diff --git a/pom.xml b/pom.xml index a66a1285a..6aefafccf 100644 --- a/pom.xml +++ b/pom.xml @@ -134,8 +134,10 @@ Copyright (c) 2012 - Jeremy Long 2.5.3 2.9.1 2.4 + + 3.2 3.0.1 - + 2.7 2.16 2.4 From 621ac3b6ec80a7488ca127373d0c53797ddaa84f Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sat, 4 Jul 2015 06:38:39 -0400 Subject: [PATCH 17/41] changed logging level on one delete temp file log entry Former-commit-id: 2f73b9a97a641bb86b73db76dc82d5e84cde9e17 --- .../owasp/dependencycheck/utils/FileUtils.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java index 54bc64e87..b1c5b3fba 100644 --- a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java +++ b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java @@ -78,7 +78,7 @@ public final class FileUtils { boolean success = true; if (!org.apache.commons.io.FileUtils.deleteQuietly(file)) { success = false; - LOGGER.info("Failed to delete file: {}; attempting to delete on exit.", file.getPath()); + LOGGER.debug("Failed to delete file: {}; attempting to delete on exit.", file.getPath()); file.deleteOnExit(); } return success; @@ -103,16 +103,16 @@ public final class FileUtils { } /** - * Returns the data directory. If a path was specified in dependencycheck.properties or was specified using the - * Settings object, and the path exists, that path will be returned as a File object. If it does not exist, then a - * File object will be created based on the file location of the JAR containing the specified class. + * Returns the data directory. If a path was specified in dependencycheck.properties or was specified using the Settings + * object, and the path exists, that path will be returned as a File object. If it does not exist, then a File object will be + * created based on the file location of the JAR containing the specified class. * * @param configuredFilePath the configured relative or absolute path * @param clazz the class to resolve the path * @return a File object * @throws IOException is thrown if the path could not be decoded - * @deprecated This method should no longer be used. See the implementation in dependency-check-cli/App.java to see - * how the data directory should be set. + * @deprecated This method should no longer be used. See the implementation in dependency-check-cli/App.java to see how the + * data directory should be set. */ @java.lang.Deprecated public static File getDataDirectory(String configuredFilePath, Class clazz) throws IOException { @@ -126,8 +126,8 @@ public final class FileUtils { } /** - * Retrieves the physical path to the parent directory containing the provided class. For example, if a JAR file - * contained a class org.something.clazz this method would return the parent directory of the JAR file. + * Retrieves the physical path to the parent directory containing the provided class. For example, if a JAR file contained a + * class org.something.clazz this method would return the parent directory of the JAR file. * * @param clazz the class to determine the parent directory of * @return the parent directory of the file containing the specified class. From bdf2ca6e1d0de3baf85a3e264037c0acf09cf603 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sat, 4 Jul 2015 06:39:54 -0400 Subject: [PATCH 18/41] added CPE entries to patch issue #149 Former-commit-id: 2bd88a3823d5889ad12952fc3f344e69d571ad05 --- .../java/org/owasp/dependencycheck/utils/Settings.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java index 884263202..0da632208 100644 --- a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java +++ b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java @@ -130,6 +130,14 @@ public final class Settings { * The properties key for the CVE schema version 2.0. */ public static final String CVE_SCHEMA_2_0 = "cve.url-2.0.base"; + /** + * The properties key that indicates how often the CPE data needs to be updated. + */ + public static final String CPE_MODIFIED_VALID_FOR_DAYS = "cpe.validfordays"; + /** + * The properties key for the URL to retrieve the CPE. + */ + public static final String CPE_URL = "cpe.url"; /** * The properties key for the proxy server. * From 44893a2a2c32250ea7d815f323196a46e1a19316 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sat, 4 Jul 2015 06:40:39 -0400 Subject: [PATCH 19/41] added CPE entries to patch issue #149 Former-commit-id: 472d5456e6a8a9d569908ce8da4f64d05afa96c7 --- .../src/test/resources/dependencycheck.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dependency-check-core/src/test/resources/dependencycheck.properties b/dependency-check-core/src/test/resources/dependencycheck.properties index a0a7c8aad..15f1ce0a8 100644 --- a/dependency-check-core/src/test/resources/dependencycheck.properties +++ b/dependency-check-core/src/test/resources/dependencycheck.properties @@ -60,6 +60,9 @@ cve.url-1.2.base=https://nvd.nist.gov/download/nvdcve-%d.xml.gz cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz #cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml +cpe.validfordays=30 +cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.xml.gz + # the URL for searching Nexus for SHA-1 hashes and whether it's enabled analyzer.nexus.enabled=true From 7203c91c7034a71a515901924ff07757dc0914fb Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sun, 5 Jul 2015 06:09:17 -0400 Subject: [PATCH 20/41] corrected naming of cpe part update Former-commit-id: aaac06bda3480c23d663f25b1feac34dc57032b9 --- .../dependency/VulnerableSoftware.java | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java index d5e744c40..521cff011 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java @@ -57,8 +57,7 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp /** *

- * Parses a name attribute value, from the cpe.xml, into its corresponding parts: vendor, product, version, - * revision.

+ * Parses a name attribute value, from the cpe.xml, into its corresponding parts: vendor, product, version, update.

*

* Example:

*    cpe:/a:apache:struts:1.1:rc2 @@ -85,7 +84,7 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp version = urlDecode(data[2]); } if (data.length >= 4) { - revision = urlDecode(data[3]); + update = urlDecode(data[3]); } if (data.length >= 5) { edition = urlDecode(data[4]); @@ -297,26 +296,26 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp this.version = version; } /** - * The product revision version. + * The product update version. */ - private String revision; + private String update; /** - * Get the value of revision. + * Get the value of update. * - * @return the value of revision + * @return the value of update */ - public String getRevision() { - return revision; + public String getUpdate() { + return update; } /** - * Set the value of revision. + * Set the value of update. * - * @param revision new value of revision + * @param update new value of update */ - public void setRevision(String revision) { - this.revision = revision; + public void setUpdate(String update) { + this.update = update; } /** * The product edition. @@ -363,11 +362,9 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp } /** - * Call {@link java.net.URLDecoder#decode(String)} to URL decode using the - * default encoding. + * Call {@link java.net.URLDecoder#decode(String)} to URL decode using the default encoding. * - * @param text - * www-form-encoded URL to decode + * @param text www-form-encoded URL to decode * @return the newly decoded String */ @SuppressWarnings("deprecation") From da058fcaf5aa850be918a5f5d4ef37f41c16d0a5 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sun, 5 Jul 2015 06:24:55 -0400 Subject: [PATCH 21/41] corrected naming of cpe part update Former-commit-id: 1e7e29ac28d576c495f96713277eaa7c1b705cfc --- .../java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java index 4d0470f8e..8b004765e 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java @@ -511,8 +511,8 @@ public class CPEAnalyzer implements Analyzer { } for (VulnerableSoftware vs : cpes) { DependencyVersion dbVer; - if (vs.getRevision() != null && !vs.getRevision().isEmpty()) { - dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + "." + vs.getRevision()); + if (vs.getUpdate() != null && !vs.getUpdate().isEmpty()) { + dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + "." + vs.getUpdate()); } else { dbVer = DependencyVersionUtil.parseVersion(vs.getVersion()); } From 4d01d636ccfed80579b4251caef11b3a8676017a Mon Sep 17 00:00:00 2001 From: Dale Visser Date: Fri, 26 Jun 2015 18:18:07 -0400 Subject: [PATCH 22/41] Changed AbstractFiletypeAnalyzer to expose getFileFilter() instead of getSupportedExtensions(), and refactored existing implementations to return a FileFilter instance. The new FileFilterBuilder class encapsulates building of a filter that can consider the full filename or other attributes, in addition to file extension. Former-commit-id: 9c968c77cc2285d571d38b1a8486d05b09b12aa4 --- .../org/owasp/dependencycheck/Engine.java | 15 +-- .../analyzer/AbstractFileTypeAnalyzer.java | 76 ++++++------ .../analyzer/ArchiveAnalyzer.java | 46 +++---- .../analyzer/AssemblyAnalyzer.java | 41 +++---- .../analyzer/AutoconfAnalyzer.java | 32 +++-- .../analyzer/CentralAnalyzer.java | 31 ++--- .../analyzer/FileTypeAnalyzer.java | 12 +- .../dependencycheck/analyzer/JarAnalyzer.java | 25 ++-- .../analyzer/JavaScriptAnalyzer.java | 24 ++-- .../analyzer/NexusAnalyzer.java | 31 ++--- .../analyzer/NuspecAnalyzer.java | 24 ++-- .../analyzer/PythonDistributionAnalyzer.java | 59 ++++----- .../analyzer/PythonPackageAnalyzer.java | 39 +++--- .../dependencycheck/utils/ExtractionUtil.java | 3 +- .../utils/FileFilterBuilder.java | 113 ++++++++++++++++++ .../ArchiveAnalyzerIntegrationTest.java | 41 ++----- .../analyzer/AssemblyAnalyzerTest.java | 4 +- .../analyzer/AutoconfAnalyzerTest.java | 34 ++---- .../analyzer/CPEAnalyzerIntegrationTest.java | 2 +- .../analyzer/JarAnalyzerTest.java | 39 +++--- .../analyzer/JavaScriptAnalyzerTest.java | 31 ++--- .../analyzer/NuspecAnalyzerTest.java | 15 +-- .../PythonDistributionAnalyzerTest.java | 38 ++---- .../analyzer/PythonPackageAnalyzerTest.java | 29 ++--- 24 files changed, 382 insertions(+), 422 deletions(-) create mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java index 69036b9a9..a5b232990 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java @@ -37,6 +37,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.io.FileFilter; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashSet; @@ -50,7 +51,7 @@ import java.util.Set; * * @author Jeremy Long */ -public class Engine { +public class Engine implements FileFilter{ /** * The list of dependencies. @@ -317,7 +318,7 @@ public class Engine { extension = fileName; } Dependency dependency = null; - if (supportsExtension(extension)) { + if (accept(file)) { dependency = new Dependency(file); if (extension.equals(fileName)) { dependency.setFileExtension(extension); @@ -379,7 +380,7 @@ public class Engine { boolean shouldAnalyze = true; if (a instanceof FileTypeAnalyzer) { final FileTypeAnalyzer fAnalyzer = (FileTypeAnalyzer) a; - shouldAnalyze = fAnalyzer.supportsExtension(d.getFileExtension()); + shouldAnalyze = fAnalyzer.accept(d.getActualFile()); } if (shouldAnalyze) { LOGGER.debug("Begin Analysis of '{}'", d.getActualFilePath()); @@ -482,18 +483,18 @@ public class Engine { /** * Checks all analyzers to see if an extension is supported. * - * @param ext a file extension + * @param file a file extension * @return true or false depending on whether or not the file extension is supported */ - public boolean supportsExtension(String ext) { - if (ext == null) { + public boolean accept(File file) { + if (file == null) { return false; } boolean scan = false; for (FileTypeAnalyzer a : this.fileTypeAnalyzers) { /* note, we can't break early on this loop as the analyzers need to know if they have files to work on prior to initialization */ - scan |= a.supportsExtension(ext); + scan |= a.accept(file); } return scan; } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java index 78f1499d2..c431e2326 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java @@ -17,9 +17,15 @@ */ package org.owasp.dependencycheck.analyzer; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; +import java.io.File; +import java.io.FileFilter; +import java.util.*; + +import org.apache.commons.io.IOCase; +import org.apache.commons.io.filefilter.IOFileFilter; +import org.apache.commons.io.filefilter.NameFileFilter; +import org.apache.commons.io.filefilter.OrFileFilter; +import org.apache.commons.io.filefilter.SuffixFileFilter; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Dependency; @@ -36,6 +42,7 @@ import org.slf4j.LoggerFactory; public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer { // + /** * Base constructor that all children must call. This checks the configuration to determine if the analyzer is * enabled. @@ -98,21 +105,20 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen // // + /** *

- * Returns a list of supported file extensions. An example would be an analyzer that inspected java jar files. The - * getSupportedExtensions function would return a set with a single element "jar".

+ * Returns the {@link java.io.FileFilter} used to determine which files are to be analyzed. + * An example would be an analyzer that inspected Java jar files. Implementors may use + * {@link org.owasp.dependencycheck.utils.FileFilterBuilder}.

* + * @return the file filter used to determine which files are to be analyzed + *

*

- * Note: when implementing this the extensions returned MUST be lowercase.

- * - * @return The file extensions supported by this analyzer. - * - *

- * If the analyzer returns null it will not cause additional files to be analyzed but will be executed against every - * file loaded

+ * If the analyzer returns null it will not cause additional files to be analyzed, but will be executed against + * every file loaded.

*/ - protected abstract Set getSupportedExtensions(); + protected abstract FileFilter getFileFilter(); /** * Initializes the file type analyzer. @@ -126,7 +132,7 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen * scanned, and added to the list of dependencies within the engine. * * @param dependency the dependency to analyze - * @param engine the engine scanning + * @param engine the engine scanning * @throws AnalysisException thrown if there is an analysis exception */ protected abstract void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException; @@ -141,6 +147,7 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen //
// + /** * Initializes the analyzer. * @@ -175,7 +182,7 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen * scanned, and added to the list of dependencies within the engine. * * @param dependency the dependency to analyze - * @param engine the engine scanning + * @param engine the engine scanning * @throws AnalysisException thrown if there is an analysis exception */ @Override @@ -185,38 +192,30 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen } } - /** - * Returns whether or not this analyzer can process the given extension. - * - * @param extension the file extension to test for support. - * @return whether or not the specified file extension is supported by this analyzer. - */ @Override - public final boolean supportsExtension(String extension) { - if (!enabled) { - return false; - } - final Set ext = getSupportedExtensions(); - if (ext == null) { - LOGGER.error("The '{}' analyzer is misconfigured and does not have any file extensions;" - + " it will be disabled", getName()); - return false; - } else { - final boolean match = ext.contains(extension); - if (match) { - filesMatched = match; + public boolean accept(File pathname) { + FileFilter filter = getFileFilter(); + boolean accepted = false; + if (null == filter) { + LOGGER.error("The '{}' analyzer is misconfigured and does not have a file filter; it will be disabled", getName()); + } else if (enabled) { + accepted = filter.accept(pathname); + if (accepted) { + filesMatched = true; } - return match; } + return accepted; } -// + + // // + /** *

* Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a * final static declaration.

- * + *

*

* This implementation was copied from * http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction

@@ -226,9 +225,10 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen */ protected static Set newHashSet(String... strings) { final Set set = new HashSet(); - Collections.addAll(set, strings); return set; } + + //
} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java index 28cd78a2a..ebe2eb19e 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java @@ -17,13 +17,7 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; +import java.io.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -31,6 +25,7 @@ import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Set; + import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; @@ -44,6 +39,7 @@ import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException; import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.FileUtils; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; @@ -116,14 +112,11 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { EXTENSIONS.addAll(ZIPPABLES); } - /** - * Returns a list of file EXTENSIONS supported by this analyzer. - * - * @return a list of file EXTENSIONS supported by this analyzer. - */ + private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build(); + @Override - public Set getSupportedExtensions() { - return EXTENSIONS; + protected FileFilter getFileFilter() { + return FILTER; } /** @@ -197,7 +190,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { * scanned, and added to the list of dependencies within the engine. * * @param dependency the dependency to analyze - * @param engine the engine scanning + * @param engine the engine scanning * @throws AnalysisException thrown if there is an analysis exception */ @Override @@ -229,14 +222,14 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { //TODO - can we get more evidence from the parent? EAR contains module name, etc. //analyze the dependency (i.e. extract files) if it is a supported type. - if (this.supportsExtension(d.getFileExtension()) && scanDepth < MAX_SCAN_DEPTH) { + if (this.accept(d.getActualFile()) && scanDepth < MAX_SCAN_DEPTH) { scanDepth += 1; analyze(d, engine); scanDepth -= 1; } } } - if (this.REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) { + if (REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) { if ("zip".equals(dependency.getFileExtension()) && isZipFileActuallyJarFile(dependency)) { final File tdir = getNextTempDirectory(); final String fileName = dependency.getFileName(); @@ -295,9 +288,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { /** * Extracts the contents of an archive into the specified directory. * - * @param archive an archive file such as a WAR or EAR + * @param archive an archive file such as a WAR or EAR * @param destination a directory to extract the contents to - * @param engine the scanning engine + * @param engine the scanning engine * @throws AnalysisException thrown if the archive is not found */ private void extractFiles(File archive, File destination, Engine engine) throws AnalysisException { @@ -320,9 +313,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { extractArchive(new TarArchiveInputStream(new BufferedInputStream(fis)), destination, engine); } else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) { final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName()); - final String uncompressedExt = FileUtils.getFileExtension(uncompressedName).toLowerCase(); - if (engine.supportsExtension(uncompressedExt)) { - decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), new File(destination, uncompressedName)); + File f = new File(destination, uncompressedName); + if (engine.accept(f)) { + decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), f); } } } catch (ArchiveExtractionException ex) { @@ -343,9 +336,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { /** * Extracts files from an archive. * - * @param input the archive to extract files from + * @param input the archive to extract files from * @param destination the location to write the files too - * @param engine the dependency-check engine + * @param engine the dependency-check engine * @throws ArchiveExtractionException thrown if there is an exception extracting files from the archive */ private void extractArchive(ArchiveInputStream input, File destination, Engine engine) throws ArchiveExtractionException { @@ -362,8 +355,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { } } else { final File file = new File(destination, entry.getName()); - final String ext = FileUtils.getFileExtension(file.getName()); - if (engine.supportsExtension(ext)) { + if (engine.accept(file)) { LOGGER.debug("Extracting '{}'", file.getPath()); BufferedOutputStream bos = null; FileOutputStream fos = null; @@ -429,7 +421,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { * Decompresses a file. * * @param inputStream the compressed file - * @param outputFile the location to write the decompressed file + * @param outputFile the location to write the decompressed file * @throws ArchiveExtractionException thrown if there is an exception decompressing the file */ private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException { diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java index f8eade81e..70701ced8 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java @@ -17,22 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - import ch.qos.cal10n.IMessageConveyor; import ch.qos.cal10n.MessageConveyor; import org.owasp.dependencycheck.Engine; @@ -41,12 +25,23 @@ import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Evidence; import org.owasp.dependencycheck.utils.DCResources; +import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.cal10n.LocLogger; import org.slf4j.cal10n.LocLoggerFactory; import org.w3c.dom.Document; import org.xml.sax.SAXException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + /** * Analyzer for getting company, product, and version information from a .NET assembly. * @@ -66,7 +61,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer { /** * The list of supported extensions */ - private static final Set SUPPORTED_EXTENSIONS = newHashSet("dll", "exe"); + private static final String[] SUPPORTED_EXTENSIONS = {"dll", "exe"}; /** * The temp value for GrokAssembly.exe */ @@ -296,14 +291,12 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer { } } - /** - * Gets the set of extensions supported by this analyzer. - * - * @return the list of supported extensions - */ + private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions( + SUPPORTED_EXTENSIONS).build(); + @Override - public Set getSupportedExtensions() { - return SUPPORTED_EXTENSIONS; + protected FileFilter getFileFilter() { + return FILTER; } /** diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java index 1e81a0df6..f23e546a2 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java @@ -17,23 +17,24 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.EvidenceCollection; +import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.UrlStringUtils; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Used to analyze Autoconf input files named configure.ac or configure.in. Files simply named "configure" are also analyzed, * assuming they are generated by Autoconf, and contain certain special package descriptor variables. @@ -71,8 +72,7 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer { /** * The set of file extensions supported by this analyzer. */ - private static final Set EXTENSIONS = newHashSet("ac", "in", - CONFIGURE); + private static final String[] EXTENSIONS = {"ac", "in"}; /** * Matches AC_INIT variables in the output configure script. @@ -103,14 +103,12 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer { | Pattern.CASE_INSENSITIVE); } - /** - * Returns a list of file EXTENSIONS supported by this analyzer. - * - * @return a list of file EXTENSIONS supported by this analyzer. - */ + private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFilenames(CONFIGURE).addExtensions( + EXTENSIONS).build(); + @Override - public Set getSupportedExtensions() { - return EXTENSIONS; + protected FileFilter getFileFilter() { + return FILTER; } /** diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java index 94074deb7..029f25c45 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java @@ -17,12 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.URL; -import java.util.List; -import java.util.Set; import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; @@ -31,14 +25,18 @@ import org.owasp.dependencycheck.data.nexus.MavenArtifact; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Evidence; +import org.owasp.dependencycheck.utils.*; import org.owasp.dependencycheck.xml.pom.PomUtils; -import org.owasp.dependencycheck.utils.DownloadFailedException; -import org.owasp.dependencycheck.utils.Downloader; -import org.owasp.dependencycheck.utils.InvalidSettingException; -import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileFilter; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.util.List; + /** * Analyzer which will attempt to locate a dependency, and the GAV information, by querying Central for the dependency's SHA-1 * digest. @@ -65,7 +63,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer { /** * The types of files on which this will work. */ - private static final Set SUPPORTED_EXTENSIONS = newHashSet("jar"); + private static final String SUPPORTED_EXTENSIONS = "jar"; /** * The analyzer should be disabled if there are errors, so this is a flag to determine if such an error has occurred. @@ -163,14 +161,11 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer { return ANALYSIS_PHASE; } - /** - * Returns the extensions for which this Analyzer runs. - * - * @return the extensions for which this Analyzer runs - */ + private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build(); + @Override - public Set getSupportedExtensions() { - return SUPPORTED_EXTENSIONS; + protected FileFilter getFileFilter() { + return FILTER; } /** diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileTypeAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileTypeAnalyzer.java index 0151578c6..bb7467a4c 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileTypeAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileTypeAnalyzer.java @@ -17,20 +17,14 @@ */ package org.owasp.dependencycheck.analyzer; +import java.io.FileFilter; + /** * An Analyzer that scans specific file types. * * @author Jeremy Long */ -public interface FileTypeAnalyzer extends Analyzer { - - /** - * Returns whether or not this analyzer can process the given extension. - * - * @param extension the file extension to test for support. - * @return whether or not the specified file extension is supported by this analyzer. - */ - boolean supportsExtension(String extension); +public interface FileTypeAnalyzer extends Analyzer, FileFilter { /** * Resets the analyzers state. diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java index f9c180446..94aaceb37 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java @@ -17,14 +17,7 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; +import java.io.*; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; @@ -47,6 +40,7 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.EvidenceCollection; +import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.xml.pom.License; import org.owasp.dependencycheck.xml.pom.PomUtils; import org.owasp.dependencycheck.xml.pom.Model; @@ -168,16 +162,13 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer { /** * The set of file extensions supported by this analyzer. */ - private static final Set EXTENSIONS = newHashSet("jar", "war"); + private static final String[] EXTENSIONS = {"jar", "war"}; + + private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build(); - /** - * Returns a list of file EXTENSIONS supported by this analyzer. - * - * @return a list of file EXTENSIONS supported by this analyzer. - */ @Override - public Set getSupportedExtensions() { - return EXTENSIONS; + protected FileFilter getFileFilter() { + return FILTER; } /** @@ -388,7 +379,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer { * @param dependency the dependency being analyzed * @return returns the POM object * @throws AnalysisException is thrown if there is an exception extracting or parsing the POM - * {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object + * {@link org.owasp.dependencycheck.xml.pom.Model} object */ private Model extractPom(String path, JarFile jar, Dependency dependency) throws AnalysisException { InputStream input = null; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzer.java index 077a6d667..6af9c3a8c 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzer.java @@ -17,20 +17,17 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.util.Set; -import java.util.regex.Pattern; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.*; +import java.util.regex.Pattern; + /** * * Used to analyze a JavaScript file to gather information to aid in identification of a CPE identifier. @@ -56,16 +53,13 @@ public class JavaScriptAnalyzer extends AbstractFileTypeAnalyzer { /** * The set of file extensions supported by this analyzer. */ - private static final Set EXTENSIONS = newHashSet("js"); + private static final String EXTENSIONS = "js"; + + private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build(); - /** - * Returns a list of file EXTENSIONS supported by this analyzer. - * - * @return a list of file EXTENSIONS supported by this analyzer. - */ @Override - public Set getSupportedExtensions() { - return EXTENSIONS; + protected FileFilter getFileFilter() { + return FILTER; } /** diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java index 101163745..057a1e23a 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java @@ -17,12 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Set; import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; @@ -31,14 +25,18 @@ import org.owasp.dependencycheck.data.nexus.NexusSearch; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Evidence; +import org.owasp.dependencycheck.utils.*; import org.owasp.dependencycheck.xml.pom.PomUtils; -import org.owasp.dependencycheck.utils.InvalidSettingException; -import org.owasp.dependencycheck.utils.DownloadFailedException; -import org.owasp.dependencycheck.utils.Downloader; -import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileFilter; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + /** * Analyzer which will attempt to locate a dependency on a Nexus service by SHA-1 digest of the dependency. * @@ -78,7 +76,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer { /** * The types of files on which this will work. */ - private static final Set SUPPORTED_EXTENSIONS = newHashSet("jar"); + private static final String SUPPORTED_EXTENSIONS = "jar"; /** * The Nexus Search to be set up for this analyzer. @@ -183,14 +181,11 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer { return ANALYSIS_PHASE; } - /** - * Returns the extensions for which this Analyzer runs. - * - * @return the extensions for which this Analyzer runs - */ + private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build(); + @Override - public Set getSupportedExtensions() { - return SUPPORTED_EXTENSIONS; + protected FileFilter getFileFilter() { + return FILTER; } /** diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java index 237b349ae..0082963b6 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java @@ -17,10 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Set; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.nuget.NugetPackage; @@ -29,10 +25,16 @@ import org.owasp.dependencycheck.data.nuget.NuspecParser; import org.owasp.dependencycheck.data.nuget.XPathNuspecParser; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + /** * Analyzer which will parse a Nuspec file to gather module information. * @@ -58,7 +60,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer { /** * The types of files on which this will work. */ - private static final Set SUPPORTED_EXTENSIONS = newHashSet("nuspec"); + private static final String SUPPORTED_EXTENSIONS = "nuspec"; /** * Initializes the analyzer once before any analysis is performed. @@ -99,14 +101,12 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer { return ANALYSIS_PHASE; } - /** - * Returns the extensions for which this Analyzer runs. - * - * @return the extensions for which this Analyzer runs - */ + private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions( + SUPPORTED_EXTENSIONS).build(); + @Override - public Set getSupportedExtensions() { - return SUPPORTED_EXTENSIONS; + protected FileFilter getFileFilter() { + return FILTER; } /** diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java index 6b31c6973..530837945 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java @@ -17,17 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FilenameFilter; -import java.util.Set; -import java.util.regex.Pattern; - -import javax.mail.MessagingException; -import javax.mail.internet.InternetHeaders; - import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.io.filefilter.SuffixFileFilter; import org.apache.commons.io.input.AutoCloseInputStream; @@ -37,14 +26,15 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.EvidenceCollection; -import org.owasp.dependencycheck.utils.ExtractionException; -import org.owasp.dependencycheck.utils.ExtractionUtil; -import org.owasp.dependencycheck.utils.FileUtils; -import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.utils.UrlStringUtils; +import org.owasp.dependencycheck.utils.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.mail.MessagingException; +import javax.mail.internet.InternetHeaders; +import java.io.*; +import java.util.regex.Pattern; + /** * Used to analyze a Wheel or egg distribution files, or their contents in unzipped form, and collect information that can be used * to determine the associated CPE. @@ -86,11 +76,10 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer { /** * The set of file extensions supported by this analyzer. */ - private static final Set EXTENSIONS = newHashSet("whl", "egg", - "zip", METADATA, PKG_INFO); + private static final String[] EXTENSIONS = {"whl", "egg", "zip"}; /** - * Used to match on egg archive candidate extenssions. + * Used to match on egg archive candidate extensions. */ private static final Pattern EGG_OR_ZIP = Pattern.compile("egg|zip"); @@ -114,23 +103,21 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer { /** * Filter that detects files named "METADATA". */ - private static final FilenameFilter METADATA_FILTER = new NameFileFilter( + private static final NameFileFilter METADATA_FILTER = new NameFileFilter( METADATA); /** * Filter that detects files named "PKG-INFO". */ - private static final FilenameFilter PKG_INFO_FILTER = new NameFileFilter( + private static final NameFileFilter PKG_INFO_FILTER = new NameFileFilter( PKG_INFO); - /** - * Returns a list of file EXTENSIONS supported by this analyzer. - * - * @return a list of file EXTENSIONS supported by this analyzer. - */ + private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFileFilters( + METADATA_FILTER, PKG_INFO_FILTER).addExtensions(EXTENSIONS).build(); + @Override - public Set getSupportedExtensions() { - return EXTENSIONS; + protected FileFilter getFileFilter() { + return FILTER; } /** @@ -194,13 +181,13 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer { /** * Collects the meta data from an archive. * - * @param dependency the archive being scanned - * @param folderFilter the filter to apply to the folder + * @param dependency the archive being scanned + * @param folderFilter the filter to apply to the folder * @param metadataFilter the filter to apply to the meta data * @throws AnalysisException thrown when there is a problem analyzing the dependency */ private void collectMetadataFromArchiveFormat(Dependency dependency, - FilenameFilter folderFilter, FilenameFilter metadataFilter) + FilenameFilter folderFilter, FilenameFilter metadataFilter) throws AnalysisException { final File temp = getNextTempDirectory(); LOGGER.debug("{} exists? {}", temp, temp.exists()); @@ -260,7 +247,7 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer { * Gathers evidence from the METADATA file. * * @param dependency the dependency being analyzed - * @param file a reference to the manifest/properties file + * @param file a reference to the manifest/properties file * @throws AnalysisException thrown when there is an error */ private static void collectWheelMetadata(Dependency dependency, File file) @@ -290,13 +277,13 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer { /** * Adds a value to the evidence collection. * - * @param headers the properties collection - * @param evidence the evidence collection to add the value - * @param property the property name + * @param headers the properties collection + * @param evidence the evidence collection to add the value + * @param property the property name * @param confidence the confidence of the evidence */ private static void addPropertyToEvidence(InternetHeaders headers, - EvidenceCollection evidence, String property, Confidence confidence) { + EvidenceCollection evidence, String property, Confidence confidence) { final String value = headers.getHeader(property, null); LOGGER.debug("Property: {}, Value: {}", property, value); if (StringUtils.isNotBlank(value)) { diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java index a2080792f..6aba3e1f6 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java @@ -17,17 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.io.filefilter.SuffixFileFilter; @@ -36,11 +25,21 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.EvidenceCollection; +import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.UrlStringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Used to analyze a Python package, and collect information that can be used to determine the associated CPE. * @@ -63,8 +62,7 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer { /** * Filename extensions for files to be analyzed. */ - private static final Set EXTENSIONS = Collections - .unmodifiableSet(Collections.singleton("py")); + private static final String EXTENSIONS = "py"; /** * Pattern for matching the module docstring in a source file. @@ -134,14 +132,11 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer { return AnalysisPhase.INFORMATION_COLLECTION; } - /** - * Returns the set of supported file extensions. - * - * @return the set of supported file extensions - */ + private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build(); + @Override - protected Set getSupportedExtensions() { - return EXTENSIONS; + protected FileFilter getFileFilter() { + return FILTER; } /** @@ -209,12 +204,12 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer { */ private boolean analyzeFileContents(Dependency dependency, File file) throws AnalysisException { - String contents = ""; + String contents; try { contents = FileUtils.readFileToString(file).trim(); } catch (IOException e) { throw new AnalysisException( - "Problem occured while reading dependency file.", e); + "Problem occurred while reading dependency file.", e); } boolean found = false; if (!contents.isEmpty()) { diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java index a39f01cd5..c1caa5a05 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java @@ -109,8 +109,7 @@ public final class ExtractionUtil { } } else { final File file = new File(extractTo, entry.getName()); - final String ext = getFileExtension(file.getName()); - if (engine == null || engine.supportsExtension(ext)) { + if (engine == null || engine.accept(file)) { BufferedOutputStream bos = null; FileOutputStream fos; try { diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java new file mode 100644 index 000000000..1d4ef3433 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java @@ -0,0 +1,113 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved. + */ + +package org.owasp.dependencycheck.utils; + +import org.apache.commons.io.filefilter.IOFileFilter; +import org.apache.commons.io.filefilter.NameFileFilter; +import org.apache.commons.io.filefilter.OrFileFilter; +import org.apache.commons.io.filefilter.SuffixFileFilter; + +import java.io.File; +import java.io.FileFilter; +import java.util.*; + +/** + * Utility class for building useful {@link FileFilter} instances for + * {@link org.owasp.dependencycheck.analyzer.AbstractFileTypeAnalyzer} implementations. The built filter uses + * {@link OrFileFilter} to logically OR the given filter conditions. + * + * @author Dale Visser + */ +public class FileFilterBuilder { + + public static FileFilterBuilder newInstance(){ + return new FileFilterBuilder(); + } + + private Set filenames = new HashSet(); + + /** + * Add to the set of filenames to accept for analysis. Case sensitivity is assumed. + * + * @param names one or more filenames to accept for analysis + */ + public FileFilterBuilder addFilenames(String... names) { + filenames.addAll(Arrays.asList(names)); + return this; + } + + private Set extensions = new HashSet(); + + /** + * Add to the set of file extensions to accept for analysis. Case sensitivity is assumed. + * + * @param extensions one or more file extensions to accept for analysis + */ + public FileFilterBuilder addExtensions(String... extensions) { + return this.addExtensions(Arrays.asList(extensions)); + } + + /** + * Add to the set of file extensions to accept for analysis. Case sensitivity is assumed. + * + * @param extensions one or more file extensions to accept for analysis + */ + public FileFilterBuilder addExtensions(Iterable extensions){ + for (String extension : extensions) { + // Ultimately, SuffixFileFilter will be used, and the "." needs to be explicit. + this.extensions.add(extension.startsWith(".") ? extension : "." + extension); + } + return this; + } + + private List fileFilters = new ArrayList(); + + /** + * Add to a list of {@link IOFileFilter} instances to consult for whether to accept a file for analysis. + * + * @param filters one or more file filters to consult for whether to accept for analysis + */ + public FileFilterBuilder addFileFilters(IOFileFilter... filters) { + fileFilters.addAll(Arrays.asList(filters)); + return this; + } + + /** + * Builds the filter and returns it. + * + * @return a filter that is the logical OR of all the conditions provided by the add... methods + * @throws IllegalStateException if no add... method has been called with one or more arguments + */ + public FileFilter build() { + if (filenames.isEmpty() && extensions.isEmpty() && fileFilters.isEmpty()) { + throw new IllegalStateException("May only be invoked after at least one add... method has been invoked."); + } + OrFileFilter filter = new OrFileFilter(); + if (!filenames.isEmpty()) { + filter.addFileFilter(new NameFileFilter(new ArrayList(filenames))); + } + if (!extensions.isEmpty()) { + filter.addFileFilter(new SuffixFileFilter(new ArrayList(extensions))); + } + for (IOFileFilter iof : fileFilters) { + filter.addFileFilter(iof); + } + return filter; + } +} diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerIntegrationTest.java index 38fd60298..abd94ee62 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerIntegrationTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerIntegrationTest.java @@ -20,8 +20,7 @@ package org.owasp.dependencycheck.analyzer; import java.io.File; import java.util.HashSet; import java.util.Set; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import org.junit.Test; import org.owasp.dependencycheck.BaseTest; import org.owasp.dependencycheck.Engine; @@ -39,7 +38,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase { * Test of getSupportedExtensions method, of class ArchiveAnalyzer. */ @Test - public void testGetSupportedExtensions() { + public void testSupportsExtensions() { ArchiveAnalyzer instance = new ArchiveAnalyzer(); Set expResult = new HashSet(); expResult.add("zip"); @@ -52,8 +51,9 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase { expResult.add("tar"); expResult.add("gz"); expResult.add("tgz"); - Set result = instance.getSupportedExtensions(); - assertEquals(expResult, result); + for (String ext : expResult) { + assertTrue(ext, instance.accept(new File("test." + ext))); + } } /** @@ -72,28 +72,9 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase { */ @Test public void testSupportsExtension() { - String extension = "7z"; //not supported + String extension = "test.7z"; //not supported ArchiveAnalyzer instance = new ArchiveAnalyzer(); - boolean expResult = false; - boolean result = instance.supportsExtension(extension); - assertEquals(expResult, result); - - extension = "war"; //supported - expResult = true; - result = instance.supportsExtension(extension); - assertEquals(expResult, result); - - extension = "ear"; //supported - result = instance.supportsExtension(extension); - assertEquals(expResult, result); - - extension = "zip"; //supported - result = instance.supportsExtension(extension); - assertEquals(expResult, result); - - extension = "nupkg"; //supported - result = instance.supportsExtension(extension); - assertEquals(expResult, result); + assertFalse(extension, instance.accept(new File(extension))); } /** @@ -129,7 +110,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase { public void testAnalyze() throws Exception { ArchiveAnalyzer instance = new ArchiveAnalyzer(); //trick the analyzer into thinking it is active. - instance.supportsExtension("ear"); + instance.accept(new File("test.ear")); try { instance.initialize(); File file = BaseTest.getResourceAsFile(this, "daytrader-ear-2.1.7.ear"); @@ -160,7 +141,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase { public void testAnalyzeTar() throws Exception { ArchiveAnalyzer instance = new ArchiveAnalyzer(); //trick the analyzer into thinking it is active so that it will initialize - instance.supportsExtension("tar"); + instance.accept(new File("test.tar")); try { instance.initialize(); @@ -191,7 +172,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase { @Test public void testAnalyzeTarGz() throws Exception { ArchiveAnalyzer instance = new ArchiveAnalyzer(); - instance.supportsExtension("zip"); //ensure analyzer is "enabled" + instance.accept(new File("zip")); //ensure analyzer is "enabled" try { instance.initialize(); @@ -244,7 +225,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase { @Test public void testAnalyzeTgz() throws Exception { ArchiveAnalyzer instance = new ArchiveAnalyzer(); - instance.supportsExtension("zip"); //ensure analyzer is "enabled" + instance.accept(new File("zip")); //ensure analyzer is "enabled" try { instance.initialize(); diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzerTest.java index 3333227a3..d67c417fd 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzerTest.java @@ -58,7 +58,7 @@ public class AssemblyAnalyzerTest extends BaseTest { public void setUp() throws Exception { try { analyzer = new AssemblyAnalyzer(); - analyzer.supportsExtension("dll"); + analyzer.accept(new File("test.dll")); // trick into "thinking it is active" analyzer.initialize(); } catch (Exception e) { if (e.getMessage().contains("Could not execute .NET AssemblyAnalyzer")) { @@ -155,7 +155,7 @@ public class AssemblyAnalyzerTest extends BaseTest { System.setProperty(LOG_KEY, "error"); // Have to make a NEW analyzer because during setUp, it would have gotten the correct one AssemblyAnalyzer aanalyzer = new AssemblyAnalyzer(); - aanalyzer.supportsExtension("dll"); + aanalyzer.accept(new File("test.dll")); // trick into "thinking it is active" aanalyzer.initialize(); fail("Expected an AnalysisException"); } catch (AnalysisException ae) { diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzerTest.java index 6e118e41a..d6f8bb79c 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzerTest.java @@ -17,13 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; -import java.util.HashSet; - -import org.apache.commons.lang.StringUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -31,6 +24,11 @@ import org.owasp.dependencycheck.BaseTest; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Dependency; +import java.io.File; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** * Unit tests for AutoconfAnalyzer. The test resources under autoconf/ were * obtained from outside open source software projects. Links to those projects @@ -164,27 +162,15 @@ public class AutoconfAnalyzerTest extends BaseTest { } /** - * Test of {@link AutoconfAnalyzer#getSupportedExtensions}. + * Test of {@link AutoconfAnalyzer#accept(File)}. */ @Test - public void testGetSupportedExtensions() { - final String[] expected = { "ac", "in", "configure" }; - assertEquals("Supported extensions should just have the following: " - + StringUtils.join(expected, ", "), - new HashSet(Arrays.asList(expected)), - analyzer.getSupportedExtensions()); - } - - /** - * Test of {@link AutoconfAnalyzer#supportsExtension}. - */ - @Test - public void testSupportsExtension() { + public void testSupportsFileExtension() { assertTrue("Should support \"ac\" extension.", - analyzer.supportsExtension("ac")); + analyzer.accept(new File("configure.ac"))); assertTrue("Should support \"in\" extension.", - analyzer.supportsExtension("in")); + analyzer.accept(new File("configure.in"))); assertTrue("Should support \"configure\" extension.", - analyzer.supportsExtension("configure")); + analyzer.accept(new File("configure"))); } } \ No newline at end of file diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java index 3625537a3..404d57ece 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java @@ -149,7 +149,7 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase { HintAnalyzer hintAnalyzer = new HintAnalyzer(); JarAnalyzer jarAnalyzer = new JarAnalyzer(); - jarAnalyzer.supportsExtension("jar"); + jarAnalyzer.accept(new File("test.jar"));//trick analyzer into "thinking it is active" jarAnalyzer.analyze(struts, null); hintAnalyzer.analyze(struts, null); diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java index 6ffebbda1..90f345cd7 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java @@ -17,19 +17,19 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.File; -import java.util.HashSet; -import java.util.Properties; -import java.util.Set; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import org.junit.Test; import org.owasp.dependencycheck.BaseTest; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Evidence; +import java.io.File; +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** - * * @author Jeremy Long */ public class JarAnalyzerTest extends BaseTest { @@ -94,13 +94,14 @@ public class JarAnalyzerTest extends BaseTest { * Test of getSupportedExtensions method, of class JarAnalyzer. */ @Test - public void testGetSupportedExtensions() { + public void testAcceptSupportedExtensions() throws Exception { JarAnalyzer instance = new JarAnalyzer(); - Set expResult = new HashSet(); - expResult.add("jar"); - expResult.add("war"); - Set result = instance.getSupportedExtensions(); - assertEquals(expResult, result); + instance.initialize(); + instance.setEnabled(true); + String[] files = {"test.jar", "test.war"}; + for (String name : files) { + assertTrue(name, instance.accept(new File(name))); + } } /** @@ -114,16 +115,4 @@ public class JarAnalyzerTest extends BaseTest { assertEquals(expResult, result); } - /** - * Test of supportsExtension method, of class JarAnalyzer. - */ - @Test - public void testSupportsExtension() { - String extension = "jar"; - JarAnalyzer instance = new JarAnalyzer(); - boolean expResult = true; - boolean result = instance.supportsExtension(extension); - assertEquals(expResult, result); - } - } diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzerTest.java index 8daf030ed..fb1169039 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzerTest.java @@ -17,15 +17,16 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.File; -import java.util.HashSet; -import java.util.Set; -import static org.junit.Assert.assertEquals; import org.junit.Test; import org.owasp.dependencycheck.BaseTest; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.dependency.Dependency; +import java.io.File; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** * * @author Jeremy Long @@ -36,12 +37,12 @@ public class JavaScriptAnalyzerTest extends BaseTest { * Test of getSupportedExtensions method, of class JavaScriptAnalyzer. */ @Test - public void testGetSupportedExtensions() { + public void testAcceptSupportedExtensions() throws Exception { JavaScriptAnalyzer instance = new JavaScriptAnalyzer(); - Set expResult = new HashSet(); - expResult.add("js"); - Set result = instance.getSupportedExtensions(); - assertEquals(expResult, result); + instance.initialize(); + instance.setEnabled(true); + String name = "test.js"; + assertTrue(name, instance.accept(new File(name))); } /** @@ -56,18 +57,6 @@ public class JavaScriptAnalyzerTest extends BaseTest { assertEquals(expResult, result); } - /** - * Test of supportsExtension method, of class JavaScriptAnalyzer. - */ - @Test - public void testSupportsExtension() { - String extension = "js"; - JavaScriptAnalyzer instance = new JavaScriptAnalyzer(); - boolean expResult = true; - boolean result = instance.supportsExtension(extension); - assertEquals(expResult, result); - } - /** * Test of getAnalysisPhase method, of class JavaScriptAnalyzer. */ diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java index b993c6159..6d184dd2a 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java @@ -24,6 +24,8 @@ import org.junit.Before; import org.junit.Test; import org.owasp.dependencycheck.BaseTest; +import java.io.File; + public class NuspecAnalyzerTest extends BaseTest { private NuspecAnalyzer instance; @@ -31,6 +33,7 @@ public class NuspecAnalyzerTest extends BaseTest { @Before public void setUp() throws Exception { instance = new NuspecAnalyzer(); + instance.initialize(); instance.setEnabled(true); } @@ -40,15 +43,9 @@ public class NuspecAnalyzerTest extends BaseTest { } @Test - public void testGetSupportedExtensions() { - assertTrue(instance.getSupportedExtensions().contains("nuspec")); - assertFalse(instance.getSupportedExtensions().contains("nupkg")); - } - - @Test - public void testSupportsExtension() { - assertTrue(instance.supportsExtension("nuspec")); - assertFalse(instance.supportsExtension("nupkg")); + public void testSupportsFileExtensions() { + assertTrue(instance.accept(new File("test.nuspec"))); + assertFalse(instance.accept(new File("test.nupkg"))); } @Test diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzerTest.java index 2a2018884..ded6cb20b 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzerTest.java @@ -17,13 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; -import java.util.HashSet; - -import org.apache.commons.lang.StringUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -32,6 +25,11 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Evidence; +import java.io.File; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** * Unit tests for PythonDistributionAnalyzer. * @@ -76,33 +74,21 @@ public class PythonDistributionAnalyzerTest extends BaseTest { analyzer.getName()); } - /** - * Test of getSupportedExtensions method, of class PythonDistributionAnalyzer. - */ - @Test - public void testGetSupportedExtensions() { - final String[] expected = {"whl", "egg", "zip", "METADATA", "PKG-INFO"}; - assertEquals("Supported extensions should just have the following: " - + StringUtils.join(expected, ", "), - new HashSet(Arrays.asList(expected)), - analyzer.getSupportedExtensions()); - } - /** * Test of supportsExtension method, of class PythonDistributionAnalyzer. */ @Test - public void testSupportsExtension() { + public void testSupportsFiles() { assertTrue("Should support \"whl\" extension.", - analyzer.supportsExtension("whl")); + analyzer.accept(new File("test.whl"))); assertTrue("Should support \"egg\" extension.", - analyzer.supportsExtension("egg")); + analyzer.accept(new File("test.egg"))); assertTrue("Should support \"zip\" extension.", - analyzer.supportsExtension("zip")); + analyzer.accept(new File("test.zip"))); assertTrue("Should support \"METADATA\" extension.", - analyzer.supportsExtension("METADATA")); + analyzer.accept(new File("METADATA"))); assertTrue("Should support \"PKG-INFO\" extension.", - analyzer.supportsExtension("PKG-INFO")); + analyzer.accept(new File("PKG-INFO"))); } /** @@ -119,7 +105,7 @@ public class PythonDistributionAnalyzerTest extends BaseTest { /** * Test of inspect method, of class PythonDistributionAnalyzer. * - * @throws Exception is thrown when an exception occurs. + * @throws AnalysisException is thrown when an exception occurs. */ @Test public void testAnalyzeSitePackage() throws AnalysisException { diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzerTest.java index 0b13dd153..b132c2ec8 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzerTest.java @@ -17,15 +17,7 @@ */ package org.owasp.dependencycheck.analyzer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; -import java.util.HashSet; - -import org.apache.commons.lang.StringUtils; import org.junit.After; -import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; import org.owasp.dependencycheck.BaseTest; @@ -33,6 +25,11 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Evidence; +import java.io.File; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** * Unit tests for PythonPackageAnalyzer. * @@ -77,25 +74,13 @@ public class PythonPackageAnalyzerTest extends BaseTest { analyzer.getName()); } - /** - * Test of getSupportedExtensions method, of class PythonPackageAnalyzer. - */ - @Test - public void testGetSupportedExtensions() { - final String[] expected = {"py"}; - assertEquals("Supported extensions should just have the following: " - + StringUtils.join(expected, ", "), - new HashSet(Arrays.asList(expected)), - analyzer.getSupportedExtensions()); - } - /** * Test of supportsExtension method, of class PythonPackageAnalyzer. */ @Test - public void testSupportsExtension() { + public void testSupportsFileExtension() { assertTrue("Should support \"py\" extension.", - analyzer.supportsExtension("py")); + analyzer.accept(new File("test.py"))); } @Test From e3256e4bb9ca15a3c29c0b2a1678b3a21943dbb1 Mon Sep 17 00:00:00 2001 From: Dale Visser Date: Mon, 6 Jul 2015 13:44:08 -0400 Subject: [PATCH 23/41] Removed unused imports from AbstractFileTypeAnalyzer. Former-commit-id: 79af85c863a4b64a113f88c3bab75ba038bcec0b --- .../analyzer/AbstractFileTypeAnalyzer.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java index c431e2326..a59cea4ad 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java @@ -17,15 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.File; -import java.io.FileFilter; -import java.util.*; - -import org.apache.commons.io.IOCase; -import org.apache.commons.io.filefilter.IOFileFilter; -import org.apache.commons.io.filefilter.NameFileFilter; -import org.apache.commons.io.filefilter.OrFileFilter; -import org.apache.commons.io.filefilter.SuffixFileFilter; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Dependency; @@ -34,6 +25,12 @@ import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileFilter; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + /** * The base FileTypeAnalyzer that all analyzers that have specific file types they analyze should extend. * From df39b490f566c1c47b381fb0590c67478790671e Mon Sep 17 00:00:00 2001 From: Dale Visser Date: Mon, 6 Jul 2015 13:50:00 -0400 Subject: [PATCH 24/41] Made extension file filtering case-insensitive. Former-commit-id: e7bc80227edcf0d4fb9503eb39d43260b7db028e --- .../owasp/dependencycheck/utils/FileFilterBuilder.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java index 1d4ef3433..312b9f9f3 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java @@ -18,6 +18,7 @@ package org.owasp.dependencycheck.utils; +import org.apache.commons.io.IOCase; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.io.filefilter.OrFileFilter; @@ -43,7 +44,7 @@ public class FileFilterBuilder { private Set filenames = new HashSet(); /** - * Add to the set of filenames to accept for analysis. Case sensitivity is assumed. + * Add to the set of filenames to accept for analysis. Case-sensitivity is assumed. * * @param names one or more filenames to accept for analysis */ @@ -55,7 +56,7 @@ public class FileFilterBuilder { private Set extensions = new HashSet(); /** - * Add to the set of file extensions to accept for analysis. Case sensitivity is assumed. + * Add to the set of file extensions to accept for analysis. Case-insensitivity is assumed. * * @param extensions one or more file extensions to accept for analysis */ @@ -64,7 +65,7 @@ public class FileFilterBuilder { } /** - * Add to the set of file extensions to accept for analysis. Case sensitivity is assumed. + * Add to the set of file extensions to accept for analysis. Case-insensitivity is assumed. * * @param extensions one or more file extensions to accept for analysis */ @@ -103,7 +104,7 @@ public class FileFilterBuilder { filter.addFileFilter(new NameFileFilter(new ArrayList(filenames))); } if (!extensions.isEmpty()) { - filter.addFileFilter(new SuffixFileFilter(new ArrayList(extensions))); + filter.addFileFilter(new SuffixFileFilter(new ArrayList(extensions), IOCase.INSENSITIVE)); } for (IOFileFilter iof : fileFilters) { filter.addFileFilter(iof); From be506964b0034e5c9ab7a7d660eca3881192e693 Mon Sep 17 00:00:00 2001 From: Dale Visser Date: Mon, 6 Jul 2015 14:16:44 -0400 Subject: [PATCH 25/41] Fixed javadoc. Some reformatting of FileFilterBuilder. Former-commit-id: 66a81beb1f1361b16743a762f6941dfef626ca4a --- .../utils/FileFilterBuilder.java | 34 +++++++++++++------ .../dependencycheck/xml/pom/PomUtils.java | 6 ++-- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java index 312b9f9f3..25ee59726 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java @@ -24,41 +24,53 @@ import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.io.filefilter.OrFileFilter; import org.apache.commons.io.filefilter.SuffixFileFilter; -import java.io.File; import java.io.FileFilter; import java.util.*; /** - * Utility class for building useful {@link FileFilter} instances for + *

Utility class for building useful {@link FileFilter} instances for * {@link org.owasp.dependencycheck.analyzer.AbstractFileTypeAnalyzer} implementations. The built filter uses - * {@link OrFileFilter} to logically OR the given filter conditions. + * {@link OrFileFilter} to logically OR the given filter conditions. Example usage:

+ * + *
+ *     FileFilter filter = FileFilterBuilder.newInstance().addExtensions("jar", "war").build();
+ * 
* * @author Dale Visser + * @see Builder pattern */ public class FileFilterBuilder { - public static FileFilterBuilder newInstance(){ + private Set filenames = new HashSet(); + private Set extensions = new HashSet(); + private List fileFilters = new ArrayList(); + + /** + * Create a new instance and return it. This method is for convenience in using the builder pattern within a single + * statement. + * + * @return a new builder instance + */ + public static FileFilterBuilder newInstance() { return new FileFilterBuilder(); } - private Set filenames = new HashSet(); - /** * Add to the set of filenames to accept for analysis. Case-sensitivity is assumed. * * @param names one or more filenames to accept for analysis + * @return this builder */ public FileFilterBuilder addFilenames(String... names) { filenames.addAll(Arrays.asList(names)); return this; } - private Set extensions = new HashSet(); - /** * Add to the set of file extensions to accept for analysis. Case-insensitivity is assumed. * * @param extensions one or more file extensions to accept for analysis + * @return this builder */ public FileFilterBuilder addExtensions(String... extensions) { return this.addExtensions(Arrays.asList(extensions)); @@ -68,8 +80,9 @@ public class FileFilterBuilder { * Add to the set of file extensions to accept for analysis. Case-insensitivity is assumed. * * @param extensions one or more file extensions to accept for analysis + * @return this builder */ - public FileFilterBuilder addExtensions(Iterable extensions){ + public FileFilterBuilder addExtensions(Iterable extensions) { for (String extension : extensions) { // Ultimately, SuffixFileFilter will be used, and the "." needs to be explicit. this.extensions.add(extension.startsWith(".") ? extension : "." + extension); @@ -77,12 +90,11 @@ public class FileFilterBuilder { return this; } - private List fileFilters = new ArrayList(); - /** * Add to a list of {@link IOFileFilter} instances to consult for whether to accept a file for analysis. * * @param filters one or more file filters to consult for whether to accept for analysis + * @return this builder */ public FileFilterBuilder addFileFilters(IOFileFilter... filters) { fileFilters.addAll(Arrays.asList(filters)); diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomUtils.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomUtils.java index 60122969a..f3ea0b0e9 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomUtils.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomUtils.java @@ -48,8 +48,7 @@ public final class PomUtils { * * @param file the pom.xml file * @return returns a - * @throws AnalysisException is thrown if there is an exception extracting or parsing the POM - * {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object + * @throws AnalysisException is thrown if there is an exception extracting or parsing the POM {@link Model} object */ public static Model readPom(File file) throws AnalysisException { Model model = null; @@ -78,8 +77,7 @@ public final class PomUtils { * @param path the path to the pom.xml file within the jar file * @param jar the jar file to extract the pom from * @return returns a - * @throws AnalysisException is thrown if there is an exception extracting or parsing the POM - * {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object + * @throws AnalysisException is thrown if there is an exception extracting or parsing the POM {@link Model} object */ public static Model readPom(String path, JarFile jar) throws AnalysisException { final ZipEntry entry = jar.getEntry(path); From e537ce155edb7b5b8d4d3fa5867581091e2dc0f0 Mon Sep 17 00:00:00 2001 From: ma wei Date: Tue, 7 Jul 2015 13:45:21 +0800 Subject: [PATCH 26/41] upgrade the version of dependency check utils Former-commit-id: 34ef2d92888cf2e108cc0759fd1ba04fb795abe3 --- dependency-check-gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency-check-gradle/build.gradle b/dependency-check-gradle/build.gradle index 9176ae9b8..8ecbcffc1 100644 --- a/dependency-check-gradle/build.gradle +++ b/dependency-check-gradle/build.gradle @@ -47,7 +47,7 @@ dependencies { localGroovy(), gradleApi(), 'org.owasp:dependency-check-core:1.2.11', - 'org.owasp:dependency-check-utils:1.2.10' + 'org.owasp:dependency-check-utils:1.2.11' ) } From b8a32eb0866729befc85c53d55dbef28a3aced8a Mon Sep 17 00:00:00 2001 From: ma wei Date: Tue, 7 Jul 2015 13:45:55 +0800 Subject: [PATCH 27/41] add ability for customize report output directory Former-commit-id: fdf53b2768ecd38f16de676ddd35e63fcd1cfad0 --- .../extension/DependencyCheckConfigurationExtension.groovy | 2 ++ .../com/tools/security/tasks/DependencyCheckTask.groovy | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dependency-check-gradle/src/main/groovy/com/tools/security/extension/DependencyCheckConfigurationExtension.groovy b/dependency-check-gradle/src/main/groovy/com/tools/security/extension/DependencyCheckConfigurationExtension.groovy index 0a9f220fb..8e7a29ce3 100644 --- a/dependency-check-gradle/src/main/groovy/com/tools/security/extension/DependencyCheckConfigurationExtension.groovy +++ b/dependency-check-gradle/src/main/groovy/com/tools/security/extension/DependencyCheckConfigurationExtension.groovy @@ -29,4 +29,6 @@ class DependencyCheckConfigurationExtension { Integer cveStartYear = 2002 String cveUrl12Base = "https://nvd.nist.gov/download/nvdcve-%d.xml.gz" String cveUrl20Base = "https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz" + + String outputDirectory = "./reports" } diff --git a/dependency-check-gradle/src/main/groovy/com/tools/security/tasks/DependencyCheckTask.groovy b/dependency-check-gradle/src/main/groovy/com/tools/security/tasks/DependencyCheckTask.groovy index 6413a89fe..7752dd767 100644 --- a/dependency-check-gradle/src/main/groovy/com/tools/security/tasks/DependencyCheckTask.groovy +++ b/dependency-check-gradle/src/main/groovy/com/tools/security/tasks/DependencyCheckTask.groovy @@ -77,7 +77,12 @@ class DependencyCheckTask extends DefaultTask { logger.lifecycle("Generating report for project ${currentProjectName}") def reportGenerator = new ReportGenerator(currentProjectName, engine.dependencies, engine.analyzers, new CveDB().databaseProperties) - reportGenerator.generateReports("./reports/${currentProjectName}", ReportGenerator.Format.ALL) + + reportGenerator.generateReports(generateReportDirectory(currentProjectName), ReportGenerator.Format.ALL) + } + + def generateReportDirectory(String currentProjectName) { + "${project.dependencyCheck.outputDirectory}/${currentProjectName}" } def overrideProxySetting() { From ed3c806869be7631d3e740ad589ff08df50632aa Mon Sep 17 00:00:00 2001 From: ma wei Date: Tue, 7 Jul 2015 13:57:15 +0800 Subject: [PATCH 28/41] update the version of dependency-check-gradle to 0.0.5 Former-commit-id: facbe13d3bd077b5540e8c20d6b3b1bb3d1b4e3f --- dependency-check-gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency-check-gradle/build.gradle b/dependency-check-gradle/build.gradle index 8ecbcffc1..479dbdcec 100644 --- a/dependency-check-gradle/build.gradle +++ b/dependency-check-gradle/build.gradle @@ -52,7 +52,7 @@ dependencies { } group = 'com.thoughtworks.tools' -version = '0.0.4' +version = '0.0.5' apply from: 'conf/publish/local.gradle' //apply from: 'conf/publish/maven.gradle' From fed5d3efc0fc930a037b1c5dac8d2df1471f7f79 Mon Sep 17 00:00:00 2001 From: ma wei Date: Tue, 7 Jul 2015 14:08:48 +0800 Subject: [PATCH 29/41] add read-me info about customize report output directory Former-commit-id: be8ba701e31f0c90fd686e90ebbf752b96665521 --- dependency-check-gradle/README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/dependency-check-gradle/README.md b/dependency-check-gradle/README.md index 19af23fcd..242f75a07 100644 --- a/dependency-check-gradle/README.md +++ b/dependency-check-gradle/README.md @@ -93,6 +93,11 @@ If your project includes multiple sub-projects, the report will be generated for ## FAQ +> **Questions List:** +> - What if I'm behind a proxy? +> - What if my project includes multiple sub-project? How can I use this plugin for each of them including the root project? +> - How to customize the report directory? + ### What if I'm behind a proxy? Maybe you have to use proxy to access internet, in this case, you could configure proxy settings for this plugin: @@ -148,4 +153,18 @@ subprojects { } ``` -In this way, the dependency check will be executed for all projects (including root project) or just sub projects. \ No newline at end of file +In this way, the dependency check will be executed for all projects (including root project) or just sub projects. + +### How to customize the report directory? + +By default, all reports will be placed under `./reports` folder, to change the default directory, just modify it in the configuration section like this: + +```groovy +subprojects { + apply plugin: "dependency-check" + + dependencyCheck { + outputDirectory = "./customized-path/security-report" + } +} +``` \ No newline at end of file From 9daa9b6cca4b65950b2711bfc448662895603087 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 8 Jul 2015 06:20:19 -0400 Subject: [PATCH 30/41] reorganized code, made the database file name version independent so that upgrades can be made, and implemented a CPE updates per issue #149 Former-commit-id: fdb57afa28ecffdb7ca90971851844718ecb8bb9 --- .../data/nvdcve/ConnectionFactory.java | 83 +++- .../dependencycheck/data/nvdcve/CveDB.java | 43 ++- .../data/nvdcve/DatabaseProperties.java | 33 +- .../data/update/BaseUpdater.java | 86 +++++ .../data/update/CpeUpdater.java | 196 ++++++++++ .../data/update/NvdCveUpdater.java | 228 ++++++++++- .../data/update/StandardUpdate.java | 318 --------------- .../data/update/UpdateService.java | 1 + .../data/update/cpe/CPEHandler.java | 362 ++++++++++++++++++ .../dependencycheck/data/update/cpe/Cpe.java | 114 ++++++ .../update/{task => nvd}/DownloadTask.java | 10 +- .../update/{xml => nvd}/NvdCve12Handler.java | 2 +- .../update/{xml => nvd}/NvdCve20Handler.java | 2 +- .../data/update/{ => nvd}/NvdCveInfo.java | 2 +- .../update/{task => nvd}/ProcessTask.java | 6 +- .../update/{ => nvd}/UpdateableNvdCve.java | 14 +- .../update/{xml => nvd}/package-info.java | 2 +- .../data/update/task/package-info.java | 4 - ...dencycheck.data.update.CachedWebDataSource | 3 +- .../resources/data/dbStatements.properties | 3 + .../src/main/resources/data/upgrade_2.9.sql | 6 + .../main/resources/dependencycheck.properties | 6 +- .../data/nvdcve/BaseDBTestCase.java | 2 +- .../DatabasePropertiesIntegrationTest.java | 2 +- .../data/update/BaseUpdaterTest.java | 98 +++++ .../update/CpeUpdaterIntegrationTest.java | 41 ++ .../update/NvdCveUpdaterIntegrationTest.java | 61 ++- .../update/StandardUpdateIntegrationTest.java | 67 ---- .../{task => nvd}/DownloadTaskTest.java | 6 +- .../data/update/{ => nvd}/NvdCveInfoTest.java | 3 +- .../nvd/NvdCveUpdaterIntegrationTest.java | 69 ++++ .../{xml => nvd}/NvdCve_1_2_HandlerTest.java | 3 +- .../{xml => nvd}/NvdCve_2_0_HandlerTest.java | 3 +- .../{ => nvd}/UpdateableNvdCveTest.java | 4 +- .../test/resources/dependencycheck.properties | 4 +- .../owasp/dependencycheck/utils/Settings.java | 17 +- .../dependencycheck/utils/SettingsTest.java | 12 +- .../test/resources/dependencycheck.properties | 4 +- 38 files changed, 1397 insertions(+), 523 deletions(-) create mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/BaseUpdater.java create mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java delete mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/StandardUpdate.java create mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java create mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/Cpe.java rename dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/{task => nvd}/DownloadTask.java (96%) rename dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/{xml => nvd}/NvdCve12Handler.java (99%) rename dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/{xml => nvd}/NvdCve20Handler.java (99%) rename dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/{ => nvd}/NvdCveInfo.java (98%) rename dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/{task => nvd}/ProcessTask.java (97%) rename dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/{ => nvd}/UpdateableNvdCve.java (95%) rename dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/{xml => nvd}/package-info.java (89%) delete mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/package-info.java create mode 100644 dependency-check-core/src/main/resources/data/upgrade_2.9.sql create mode 100644 dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/BaseUpdaterTest.java create mode 100644 dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/CpeUpdaterIntegrationTest.java delete mode 100644 dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/StandardUpdateIntegrationTest.java rename dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/{task => nvd}/DownloadTaskTest.java (89%) rename dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/{ => nvd}/NvdCveInfoTest.java (95%) create mode 100644 dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveUpdaterIntegrationTest.java rename dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/{xml => nvd}/NvdCve_1_2_HandlerTest.java (94%) rename dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/{xml => nvd}/NvdCve_2_0_HandlerTest.java (94%) rename dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/{ => nvd}/UpdateableNvdCveTest.java (96%) diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java index a2c05f2b2..4855190a9 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java @@ -35,9 +35,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Loads the configured database driver and returns the database connection. If the embedded H2 database is used - * obtaining a connection will ensure the database file exists and that the appropriate table structure has been - * created. + * Loads the configured database driver and returns the database connection. If the embedded H2 database is used obtaining a + * connection will ensure the database file exists and that the appropriate table structure has been created. * * @author Jeremy Long */ @@ -55,6 +54,10 @@ public final class ConnectionFactory { * Resource location for SQL file used to create the database schema. */ public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql"; + /** + * Resource location for SQL file used to create the database schema. + */ + public static final String DB_STRUCTURE_UPDATE_RESOURCE = "data/upgrade_%s.sql"; /** * The database driver used to connect to the database. */ @@ -79,8 +82,8 @@ public final class ConnectionFactory { } /** - * Initializes the connection factory. Ensuring that the appropriate drivers are loaded and that a connection can be - * made successfully. + * Initializes the connection factory. Ensuring that the appropriate drivers are loaded and that a connection can be made + * successfully. * * @throws DatabaseException thrown if we are unable to connect to the database */ @@ -114,8 +117,7 @@ public final class ConnectionFactory { try { connectionString = Settings.getConnectionString( Settings.KEYS.DB_CONNECTION_STRING, - Settings.KEYS.DB_FILE_NAME, - Settings.KEYS.DB_VERSION); + Settings.KEYS.DB_FILE_NAME); } catch (IOException ex) { LOGGER.debug( "Unable to retrieve the database connection string", ex); @@ -162,13 +164,12 @@ public final class ConnectionFactory { LOGGER.debug("", dex); throw new DatabaseException("Unable to create the database structure"); } - } else { - try { - ensureSchemaVersion(conn); - } catch (DatabaseException dex) { - LOGGER.debug("", dex); - throw new DatabaseException("Database schema does not match this version of dependency-check"); - } + } + try { + ensureSchemaVersion(conn); + } catch (DatabaseException dex) { + LOGGER.debug("", dex); + throw new DatabaseException("Database schema does not match this version of dependency-check", dex); } } finally { if (conn != null) { @@ -183,8 +184,8 @@ public final class ConnectionFactory { /** * Cleans up resources and unloads any registered database drivers. This needs to be called to ensure the driver is - * unregistered prior to the finalize method being called as during shutdown the class loader used to load the - * driver may be unloaded prior to the driver being de-registered. + * unregistered prior to the finalize method being called as during shutdown the class loader used to load the driver may be + * unloaded prior to the driver being de-registered. */ public static synchronized void cleanup() { if (driver != null) { @@ -229,8 +230,7 @@ public final class ConnectionFactory { */ private static boolean h2DataFileExists() throws IOException { final File dir = Settings.getDataDirectory(); - final String name = Settings.getString(Settings.KEYS.DB_FILE_NAME); - final String fileName = String.format(name, DB_SCHEMA_VERSION); + final String fileName = Settings.getString(Settings.KEYS.DB_FILE_NAME); final File file = new File(dir, fileName); return file.exists(); } @@ -278,6 +278,46 @@ public final class ConnectionFactory { } } + private static void updateSchema(Connection conn, String schema) throws DatabaseException { + LOGGER.debug("Updating database structure"); + InputStream is; + InputStreamReader reader; + BufferedReader in = null; + String updateFile = null; + try { + updateFile = String.format(DB_STRUCTURE_UPDATE_RESOURCE, schema); + is = ConnectionFactory.class.getClassLoader().getResourceAsStream(updateFile); + reader = new InputStreamReader(is, "UTF-8"); + in = new BufferedReader(reader); + final StringBuilder sb = new StringBuilder(2110); + String tmp; + while ((tmp = in.readLine()) != null) { + sb.append(tmp); + } + Statement statement = null; + try { + statement = conn.createStatement(); + statement.execute(sb.toString()); + } catch (SQLException ex) { + LOGGER.debug("", ex); + throw new DatabaseException("Unable to update database schema", ex); + } finally { + DBUtils.closeStatement(statement); + } + } catch (IOException ex) { + final String msg = String.format("Upgrade SQL file does not exist: %s", updateFile); + throw new DatabaseException(msg, ex); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ex) { + LOGGER.trace("", ex); + } + } + } + } + /** * Uses the provided connection to check the specified schema version within the database. * @@ -288,12 +328,13 @@ public final class ConnectionFactory { ResultSet rs = null; CallableStatement cs = null; try { + //TODO convert this to use DatabaseProperties cs = conn.prepareCall("SELECT value FROM properties WHERE id = 'version'"); rs = cs.executeQuery(); if (rs.next()) { - final boolean isWrongSchema = !DB_SCHEMA_VERSION.equals(rs.getString(1)); - if (isWrongSchema) { - throw new DatabaseException("Incorrect database schema; unable to continue"); + if (!DB_SCHEMA_VERSION.equals(rs.getString(1))) { + LOGGER.debug("Updating from version: " + rs.getString(1)); + updateSchema(conn, rs.getString(1)); } } else { throw new DatabaseException("Database schema is missing"); diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java index 6d4a34f25..c06050160 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java @@ -19,6 +19,7 @@ package org.owasp.dependencycheck.data.nvdcve; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -33,6 +34,7 @@ import java.util.Map.Entry; import java.util.Properties; import java.util.ResourceBundle; import java.util.Set; +import java.util.logging.Level; import org.owasp.dependencycheck.data.cwe.CweDB; import org.owasp.dependencycheck.dependency.Reference; import org.owasp.dependencycheck.dependency.Vulnerability; @@ -766,8 +768,8 @@ public class CveDB { DependencyVersion cpeVersion; if (cpe.getVersion() != null && !cpe.getVersion().isEmpty()) { String versionText; - if (cpe.getRevision() != null && !cpe.getRevision().isEmpty()) { - versionText = String.format("%s.%s", cpe.getVersion(), cpe.getRevision()); + if (cpe.getUpdate() != null && !cpe.getUpdate().isEmpty()) { + versionText = String.format("%s.%s", cpe.getVersion(), cpe.getUpdate()); } else { versionText = cpe.getVersion(); } @@ -777,4 +779,41 @@ public class CveDB { } return cpeVersion; } + + /** + * Deletes unused dictionary entries from the database. + */ + public void deleteUnusedCpe() { + CallableStatement cs = null; + try { + cs = getConnection().prepareCall(statementBundle.getString("DELETE_UNUSED_DICT_CPE")); + cs.executeUpdate(); + } catch (SQLException ex) { + LOGGER.error("Unable to delete CPE dictionary entries", ex); + } finally { + DBUtils.closeStatement(cs); + } + } + + /** + * Merges CPE entries into the database. + * + * @param cpe the CPE identifier + * @param vendor the CPE vendor + * @param product the CPE product + */ + public void addCpe(String cpe, String vendor, String product) { + PreparedStatement ps = null; + try { + ps = getConnection().prepareCall(statementBundle.getString("ADD_DICT_CPE")); + ps.setString(1, cpe); + ps.setString(2, vendor); + ps.setString(3, product); + ps.executeUpdate(); + } catch (SQLException ex) { + LOGGER.error("Unable to add CPE dictionary entry", ex); + } finally { + DBUtils.closeStatement(ps); + } + } } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java index fc74931e3..f3ae9b50c 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java @@ -24,7 +24,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.TreeMap; -import org.owasp.dependencycheck.data.update.NvdCveInfo; +import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo; import org.owasp.dependencycheck.data.update.exception.UpdateException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,20 +41,28 @@ public class DatabaseProperties { */ private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseProperties.class); /** - * Modified key word, used as a key to store information about the modified file (i.e. the containing the last 8 - * days of updates).. + * Modified key word, used as a key to store information about the modified file (i.e. the containing the last 8 days of + * updates).. */ public static final String MODIFIED = "Modified"; /** - * The properties file key for the last updated field - used to store the last updated time of the Modified NVD CVE - * xml file. + * The properties file key for the last updated field - used to store the last updated time of the Modified NVD CVE xml file. */ public static final String LAST_UPDATED = "NVD CVE Modified"; /** - * Stores the last updated time for each of the NVD CVE files. These timestamps should be updated if we process the - * modified file within 7 days of the last update. + * Stores the last updated time for each of the NVD CVE files. These timestamps should be updated if we process the modified + * file within 7 days of the last update. */ public static final String LAST_UPDATED_BASE = "NVD CVE "; + /** + * The key for the last time the CPE data was updated. + */ + public static final String LAST_CPE_UPDATE = "LAST_CPE_UPDATE"; + /** + * The key for the database schema version. + */ + public static final String VERSION = "version"; + /** * A collection of properties about the data. */ @@ -116,8 +124,7 @@ public class DatabaseProperties { } /** - * Returns the property value for the given key. If the key is not contained in the underlying properties null is - * returned. + * Returns the property value for the given key. If the key is not contained in the underlying properties null is returned. * * @param key the property key * @return the value of the property @@ -127,8 +134,8 @@ public class DatabaseProperties { } /** - * Returns the property value for the given key. If the key is not contained in the underlying properties the - * default value is returned. + * Returns the property value for the given key. If the key is not contained in the underlying properties the default value is + * returned. * * @param key the property key * @param defaultValue the default value @@ -148,8 +155,8 @@ public class DatabaseProperties { } /** - * Returns a map of the meta data from the database properties. This primarily contains timestamps of when the NVD - * CVE information was last updated. + * Returns a map of the meta data from the database properties. This primarily contains timestamps of when the NVD CVE + * information was last updated. * * @return a map of the database meta data */ diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/BaseUpdater.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/BaseUpdater.java new file mode 100644 index 000000000..e054e9303 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/BaseUpdater.java @@ -0,0 +1,86 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update; + +import org.owasp.dependencycheck.data.nvdcve.CveDB; +import org.owasp.dependencycheck.data.nvdcve.DatabaseException; +import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; +import org.owasp.dependencycheck.data.update.exception.UpdateException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author Jeremy Long + */ +public abstract class BaseUpdater { + + /** + * Static logger. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(BaseUpdater.class); + /** + * Information about the timestamps and URLs for data that needs to be updated. + */ + private DatabaseProperties properties; + /** + * Reference to the Cve Database. + */ + private CveDB cveDB = null; + + protected CveDB getCveDB() { + return cveDB; + } + + protected DatabaseProperties getProperties() { + return properties; + } + + /** + * Closes the CVE and CPE data stores. + */ + protected void closeDataStores() { + if (cveDB != null) { + try { + cveDB.close(); + } catch (Throwable ignore) { + LOGGER.trace("Error closing the database", ignore); + } + } + } + + /** + * Opens the data store. + * + * @throws UpdateException thrown if a data store cannot be opened + */ + protected final void openDataStores() throws UpdateException { + if (cveDB != null) { + return; + } + try { + cveDB = new CveDB(); + cveDB.open(); + } catch (DatabaseException ex) { + closeDataStores(); + LOGGER.debug("Database Exception opening databases", ex); + throw new UpdateException("Error updating the database, please see the log file for more details."); + } + properties = cveDB.getDatabaseProperties(); + } +} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java new file mode 100644 index 000000000..386b5afdd --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java @@ -0,0 +1,196 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Date; +import java.util.List; +import java.util.logging.Level; +import java.util.zip.GZIPInputStream; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import org.apache.commons.io.FileUtils; +import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.LAST_CPE_UPDATE; +import org.owasp.dependencycheck.data.update.cpe.CPEHandler; +import org.owasp.dependencycheck.data.update.cpe.Cpe; +import org.owasp.dependencycheck.data.update.exception.UpdateException; +import org.owasp.dependencycheck.utils.DateUtil; +import org.owasp.dependencycheck.utils.DownloadFailedException; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; + +/** + * + * @author Jeremy Long + */ +public class CpeUpdater extends BaseUpdater implements CachedWebDataSource { + + /** + * Static logger. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(CpeUpdater.class); + + @Override + public void update() throws UpdateException { + try { + openDataStores(); + if (updateNeeded()) { + LOGGER.info("Updating the Common Platform Enumeration (CPE)"); + final File xml = downloadCpe(); + List cpes = processXML(xml); + getCveDB().deleteUnusedCpe(); + for (Cpe cpe : cpes) { + getCveDB().addCpe(cpe.getValue(), cpe.getVendor(), cpe.getProduct()); + } + final Date now = new Date(); + getProperties().save(LAST_CPE_UPDATE, Long.toString(now.getTime())); + LOGGER.info("CPE update complete"); + } + } finally { + closeDataStores(); + } + } + + /** + * Downloads the CPE XML file. + * + * @return the file reference to the CPE.xml file + * @throws UpdateException thrown if there is an issue downloading the XML file + */ + private File downloadCpe() throws UpdateException { + File xml; + final URL url; + try { + url = new URL(Settings.getString(Settings.KEYS.CPE_URL)); + xml = File.createTempFile("cpe", ".xml", Settings.getTempDirectory()); + Downloader.fetchFile(url, xml); + if (url.toExternalForm().endsWith(".xml.gz")) { + extractGzip(xml); + } + + } catch (MalformedURLException ex) { + throw new UpdateException("Invalid CPE URL", ex); + } catch (DownloadFailedException ex) { + throw new UpdateException("Unable to download CPE XML file", ex); + } catch (IOException ex) { + throw new UpdateException("Unable to create temporary file to download CPE", ex); + } + return xml; + } + + /** + * Parses the CPE XML file to return a list of CPE entries. + * + * @param xml the CPE data file + * @return the list of CPE entries + * @throws UpdateException thrown if there is an issue with parsing the XML file + */ + private List processXML(final File xml) throws UpdateException { + try { + final SAXParserFactory factory = SAXParserFactory.newInstance(); + final SAXParser saxParser = factory.newSAXParser(); + CPEHandler handler = new CPEHandler(); + saxParser.parse(xml, handler); + return handler.getData(); + } catch (ParserConfigurationException ex) { + throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Issue", ex); + } catch (SAXException ex) { + throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Exception", ex); + } catch (IOException ex) { + throw new UpdateException("Unable to parse CPE XML file due to IO Failure", ex); + } + } + + /** + * Checks to find the last time the CPE data was refreshed and if it needs to be updated. + * + * @return true if the CPE data should be refreshed + */ + private boolean updateNeeded() { + final Date now = new Date(); + final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 30); + long timestamp = 0; + String ts = getProperties().getProperty(LAST_CPE_UPDATE); + if (ts != null && ts.matches("^[0-9]+$")) { + timestamp = Long.parseLong(ts); + } + return !DateUtil.withinDateRange(timestamp, now.getTime(), days); + } + + /** + * Extracts the file contained in a gzip archive. The extracted file is placed in the exact same path as the file specified. + * + * @param file the archive file + * @throws FileNotFoundException thrown if the file does not exist + * @throws IOException thrown if there is an error extracting the file. + */ + private void extractGzip(File file) throws FileNotFoundException, IOException { + //TODO - move this to a util class as it is duplicative of (copy of) code in the DownloadTask + final String originalPath = file.getPath(); + final File gzip = new File(originalPath + ".gz"); + if (gzip.isFile() && !gzip.delete()) { + gzip.deleteOnExit(); + } + if (!file.renameTo(gzip)) { + throw new IOException("Unable to rename '" + file.getPath() + "'"); + } + final File newfile = new File(originalPath); + + final byte[] buffer = new byte[4096]; + + GZIPInputStream cin = null; + FileOutputStream out = null; + try { + cin = new GZIPInputStream(new FileInputStream(gzip)); + out = new FileOutputStream(newfile); + + int len; + while ((len = cin.read(buffer)) > 0) { + out.write(buffer, 0, len); + } + } finally { + if (cin != null) { + try { + cin.close(); + } catch (IOException ex) { + LOGGER.trace("ignore", ex); + } + } + if (out != null) { + try { + out.close(); + } catch (IOException ex) { + LOGGER.trace("ignore", ex); + } + } + if (gzip.isFile()) { + FileUtils.deleteQuietly(gzip); + } + } + } +} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java index a6b602fd8..94d03ca89 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java @@ -18,23 +18,44 @@ package org.owasp.dependencycheck.data.update; import java.net.MalformedURLException; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; +import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.MODIFIED; +import org.owasp.dependencycheck.data.update.exception.InvalidDataException; import org.owasp.dependencycheck.data.update.exception.UpdateException; +import org.owasp.dependencycheck.data.update.nvd.DownloadTask; +import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo; +import org.owasp.dependencycheck.data.update.nvd.ProcessTask; +import org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve; +import org.owasp.dependencycheck.utils.DateUtil; import org.owasp.dependencycheck.utils.DownloadFailedException; +import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Class responsible for updating the NVD CVE and CPE data stores. + * Class responsible for updating the NVD CVE data. * * @author Jeremy Long */ -public class NvdCveUpdater implements CachedWebDataSource { +public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource { /** * The logger */ private static final Logger LOGGER = LoggerFactory.getLogger(NvdCveUpdater.class); + /** + * The max thread pool size to use when downloading files. + */ + public static final int MAX_THREAD_POOL_SIZE = Settings.getInt(Settings.KEYS.MAX_DOWNLOAD_THREAD_POOL_SIZE, 3); /** *

@@ -45,9 +66,10 @@ public class NvdCveUpdater implements CachedWebDataSource { @Override public void update() throws UpdateException { try { - final StandardUpdate task = new StandardUpdate(); - if (task.isUpdateNeeded()) { - task.update(); + openDataStores(); + UpdateableNvdCve updateable = getUpdatesNeeded(); + if (updateable.isUpdateNeeded()) { + performUpdate(updateable); } } catch (MalformedURLException ex) { LOGGER.warn( @@ -61,6 +83,202 @@ public class NvdCveUpdater implements CachedWebDataSource { "If you are behind a proxy you may need to configure dependency-check to use the proxy."); } LOGGER.debug("", ex); + } finally { + closeDataStores(); } } + + /** + * Downloads the latest NVD CVE XML file from the web and imports it into the current CVE Database. + * + * @param updateable a collection of NVD CVE data file references that need to be downloaded and processed to update the + * database + * @throws UpdateException is thrown if there is an error updating the database + */ + public void performUpdate(UpdateableNvdCve updateable) throws UpdateException { + int maxUpdates = 0; + try { + for (NvdCveInfo cve : updateable) { + if (cve.getNeedsUpdate()) { + maxUpdates += 1; + } + } + if (maxUpdates <= 0) { + return; + } + if (maxUpdates > 3) { + LOGGER.info( + "NVD CVE requires several updates; this could take a couple of minutes."); + } + if (maxUpdates > 0) { + openDataStores(); + } + + final int poolSize = (MAX_THREAD_POOL_SIZE < maxUpdates) ? MAX_THREAD_POOL_SIZE : maxUpdates; + + final ExecutorService downloadExecutors = Executors.newFixedThreadPool(poolSize); + final ExecutorService processExecutor = Executors.newSingleThreadExecutor(); + final Set>> downloadFutures = new HashSet>>(maxUpdates); + for (NvdCveInfo cve : updateable) { + if (cve.getNeedsUpdate()) { + final DownloadTask call = new DownloadTask(cve, processExecutor, getCveDB(), Settings.getInstance()); + downloadFutures.add(downloadExecutors.submit(call)); + } + } + downloadExecutors.shutdown(); + + //next, move the future future processTasks to just future processTasks + final Set> processFutures = new HashSet>(maxUpdates); + for (Future> future : downloadFutures) { + Future task = null; + try { + task = future.get(); + } catch (InterruptedException ex) { + downloadExecutors.shutdownNow(); + processExecutor.shutdownNow(); + + LOGGER.debug("Thread was interrupted during download", ex); + throw new UpdateException("The download was interrupted", ex); + } catch (ExecutionException ex) { + downloadExecutors.shutdownNow(); + processExecutor.shutdownNow(); + + LOGGER.debug("Thread was interrupted during download execution", ex); + throw new UpdateException("The execution of the download was interrupted", ex); + } + if (task == null) { + downloadExecutors.shutdownNow(); + processExecutor.shutdownNow(); + LOGGER.debug("Thread was interrupted during download"); + throw new UpdateException("The download was interrupted; unable to complete the update"); + } else { + processFutures.add(task); + } + } + + for (Future future : processFutures) { + try { + final ProcessTask task = future.get(); + if (task.getException() != null) { + throw task.getException(); + } + } catch (InterruptedException ex) { + processExecutor.shutdownNow(); + LOGGER.debug("Thread was interrupted during processing", ex); + throw new UpdateException(ex); + } catch (ExecutionException ex) { + processExecutor.shutdownNow(); + LOGGER.debug("Execution Exception during process", ex); + throw new UpdateException(ex); + } finally { + processExecutor.shutdown(); + } + } + + if (maxUpdates >= 1) { //ensure the modified file date gets written (we may not have actually updated it) + getProperties().save(updateable.get(MODIFIED)); + LOGGER.info("Begin database maintenance."); + getCveDB().cleanupDatabase(); + LOGGER.info("End database maintenance."); + } + } finally { + closeDataStores(); + } + } + + /** + * Determines if the index needs to be updated. This is done by fetching the NVD CVE meta data and checking the last update + * date. If the data needs to be refreshed this method will return the NvdCveUrl for the files that need to be updated. + * + * @return the collection of files that need to be updated + * @throws MalformedURLException is thrown if the URL for the NVD CVE Meta data is incorrect + * @throws DownloadFailedException is thrown if there is an error. downloading the NVD CVE download data file + * @throws UpdateException Is thrown if there is an issue with the last updated properties file + */ + protected final UpdateableNvdCve getUpdatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException { + UpdateableNvdCve updates = null; + try { + updates = retrieveCurrentTimestampsFromWeb(); + } catch (InvalidDataException ex) { + final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page"; + LOGGER.debug(msg, ex); + throw new DownloadFailedException(msg, ex); + } catch (InvalidSettingException ex) { + LOGGER.debug("Invalid setting found when retrieving timestamps", ex); + throw new DownloadFailedException("Invalid settings", ex); + } + + if (updates == null) { + throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data"); + } + if (!getProperties().isEmpty()) { + try { + final long lastUpdated = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED, "0")); + final Date now = new Date(); + final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7); + if (lastUpdated == updates.getTimeStamp(MODIFIED)) { + updates.clear(); //we don't need to update anything. + } else if (DateUtil.withinDateRange(lastUpdated, now.getTime(), days)) { + for (NvdCveInfo entry : updates) { + if (MODIFIED.equals(entry.getId())) { + entry.setNeedsUpdate(true); + } else { + entry.setNeedsUpdate(false); + } + } + } else { //we figure out which of the several XML files need to be downloaded. + for (NvdCveInfo entry : updates) { + if (MODIFIED.equals(entry.getId())) { + entry.setNeedsUpdate(true); + } else { + long currentTimestamp = 0; + try { + currentTimestamp = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED_BASE + entry.getId(), "0")); + } catch (NumberFormatException ex) { + LOGGER.debug("Error parsing '{}' '{}' from nvdcve.lastupdated", + DatabaseProperties.LAST_UPDATED_BASE, entry.getId(), ex); + } + if (currentTimestamp == entry.getTimestamp()) { + entry.setNeedsUpdate(false); + } + } + } + } + } catch (NumberFormatException ex) { + LOGGER.warn("An invalid schema version or timestamp exists in the data.properties file."); + LOGGER.debug("", ex); + } + } + return updates; + } + + /** + * Retrieves the timestamps from the NVD CVE meta data file. + * + * @return the timestamp from the currently published nvdcve downloads page + * @throws MalformedURLException thrown if the URL for the NVD CCE Meta data is incorrect. + * @throws DownloadFailedException thrown if there is an error downloading the nvd cve meta data file + * @throws InvalidDataException thrown if there is an exception parsing the timestamps + * @throws InvalidSettingException thrown if the settings are invalid + */ + private UpdateableNvdCve retrieveCurrentTimestampsFromWeb() + throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException { + + final UpdateableNvdCve updates = new UpdateableNvdCve(); + updates.add(MODIFIED, Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL), + Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL), + false); + + final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR); + final int end = Calendar.getInstance().get(Calendar.YEAR); + final String baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0); + final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2); + for (int i = start; i <= end; i++) { + updates.add(Integer.toString(i), String.format(baseUrl20, i), + String.format(baseUrl12, i), + true); + } + return updates; + } + } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/StandardUpdate.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/StandardUpdate.java deleted file mode 100644 index d5f1c2c22..000000000 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/StandardUpdate.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2012 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.data.update; - -import java.net.MalformedURLException; -import java.util.Calendar; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import org.owasp.dependencycheck.data.nvdcve.CveDB; -import org.owasp.dependencycheck.data.nvdcve.DatabaseException; -import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; -import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.MODIFIED; -import org.owasp.dependencycheck.data.update.exception.InvalidDataException; -import org.owasp.dependencycheck.data.update.exception.UpdateException; -import org.owasp.dependencycheck.data.update.task.DownloadTask; -import org.owasp.dependencycheck.data.update.task.ProcessTask; -import org.owasp.dependencycheck.utils.DateUtil; -import org.owasp.dependencycheck.utils.DownloadFailedException; -import org.owasp.dependencycheck.utils.InvalidSettingException; -import org.owasp.dependencycheck.utils.Settings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class responsible for updating the NVDCVE data store. - * - * @author Jeremy Long - */ -public class StandardUpdate { - - /** - * Static logger. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(StandardUpdate.class); - /** - * The max thread pool size to use when downloading files. - */ - public static final int MAX_THREAD_POOL_SIZE = Settings.getInt(Settings.KEYS.MAX_DOWNLOAD_THREAD_POOL_SIZE, 3); - /** - * Information about the timestamps and URLs for data that needs to be updated. - */ - private DatabaseProperties properties; - /** - * A collection of updateable NVD CVE items. - */ - private UpdateableNvdCve updateable; - /** - * Reference to the Cve Database. - */ - private CveDB cveDB = null; - - /** - * Gets whether or not an update is needed. - * - * @return true or false depending on whether an update is needed - */ - public boolean isUpdateNeeded() { - return updateable.isUpdateNeeded(); - } - - /** - * Constructs a new Standard Update Task. - * - * @throws MalformedURLException thrown if a configured URL is malformed - * @throws DownloadFailedException thrown if a timestamp cannot be checked on a configured URL - * @throws UpdateException thrown if there is an exception generating the update task - */ - public StandardUpdate() throws MalformedURLException, DownloadFailedException, UpdateException { - openDataStores(); - properties = cveDB.getDatabaseProperties(); - updateable = updatesNeeded(); - } - - /** - *

- * Downloads the latest NVD CVE XML file from the web and imports it into the current CVE Database.

- * - * @throws UpdateException is thrown if there is an error updating the database - */ - public void update() throws UpdateException { - int maxUpdates = 0; - try { - for (NvdCveInfo cve : updateable) { - if (cve.getNeedsUpdate()) { - maxUpdates += 1; - } - } - if (maxUpdates <= 0) { - return; - } - if (maxUpdates > 3) { - LOGGER.info( - "NVD CVE requires several updates; this could take a couple of minutes."); - } - if (maxUpdates > 0) { - openDataStores(); - } - - final int poolSize = (MAX_THREAD_POOL_SIZE < maxUpdates) ? MAX_THREAD_POOL_SIZE : maxUpdates; - - final ExecutorService downloadExecutors = Executors.newFixedThreadPool(poolSize); - final ExecutorService processExecutor = Executors.newSingleThreadExecutor(); - final Set>> downloadFutures = new HashSet>>(maxUpdates); - for (NvdCveInfo cve : updateable) { - if (cve.getNeedsUpdate()) { - final DownloadTask call = new DownloadTask(cve, processExecutor, cveDB, Settings.getInstance()); - downloadFutures.add(downloadExecutors.submit(call)); - } - } - downloadExecutors.shutdown(); - - //next, move the future future processTasks to just future processTasks - final Set> processFutures = new HashSet>(maxUpdates); - for (Future> future : downloadFutures) { - Future task = null; - try { - task = future.get(); - } catch (InterruptedException ex) { - downloadExecutors.shutdownNow(); - processExecutor.shutdownNow(); - - LOGGER.debug("Thread was interrupted during download", ex); - throw new UpdateException("The download was interrupted", ex); - } catch (ExecutionException ex) { - downloadExecutors.shutdownNow(); - processExecutor.shutdownNow(); - - LOGGER.debug("Thread was interrupted during download execution", ex); - throw new UpdateException("The execution of the download was interrupted", ex); - } - if (task == null) { - downloadExecutors.shutdownNow(); - processExecutor.shutdownNow(); - LOGGER.debug("Thread was interrupted during download"); - throw new UpdateException("The download was interrupted; unable to complete the update"); - } else { - processFutures.add(task); - } - } - - for (Future future : processFutures) { - try { - final ProcessTask task = future.get(); - if (task.getException() != null) { - throw task.getException(); - } - } catch (InterruptedException ex) { - processExecutor.shutdownNow(); - LOGGER.debug("Thread was interrupted during processing", ex); - throw new UpdateException(ex); - } catch (ExecutionException ex) { - processExecutor.shutdownNow(); - LOGGER.debug("Execution Exception during process", ex); - throw new UpdateException(ex); - } finally { - processExecutor.shutdown(); - } - } - - if (maxUpdates >= 1) { //ensure the modified file date gets written (we may not have actually updated it) - properties.save(updateable.get(MODIFIED)); - LOGGER.info("Begin database maintenance."); - cveDB.cleanupDatabase(); - LOGGER.info("End database maintenance."); - } - } finally { - closeDataStores(); - } - } - - /** - * Determines if the index needs to be updated. This is done by fetching the NVD CVE meta data and checking the last update - * date. If the data needs to be refreshed this method will return the NvdCveUrl for the files that need to be updated. - * - * @return the collection of files that need to be updated - * @throws MalformedURLException is thrown if the URL for the NVD CVE Meta data is incorrect - * @throws DownloadFailedException is thrown if there is an error. downloading the NVD CVE download data file - * @throws UpdateException Is thrown if there is an issue with the last updated properties file - */ - protected final UpdateableNvdCve updatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException { - UpdateableNvdCve updates = null; - try { - updates = retrieveCurrentTimestampsFromWeb(); - } catch (InvalidDataException ex) { - final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page"; - LOGGER.debug(msg, ex); - throw new DownloadFailedException(msg, ex); - } catch (InvalidSettingException ex) { - LOGGER.debug("Invalid setting found when retrieving timestamps", ex); - throw new DownloadFailedException("Invalid settings", ex); - } - - if (updates == null) { - throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data"); - } - if (!properties.isEmpty()) { - try { - final long lastUpdated = Long.parseLong(properties.getProperty(DatabaseProperties.LAST_UPDATED, "0")); - final Date now = new Date(); - final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7); - if (lastUpdated == updates.getTimeStamp(MODIFIED)) { - updates.clear(); //we don't need to update anything. - } else if (DateUtil.withinDateRange(lastUpdated, now.getTime(), days)) { - for (NvdCveInfo entry : updates) { - if (MODIFIED.equals(entry.getId())) { - entry.setNeedsUpdate(true); - } else { - entry.setNeedsUpdate(false); - } - } - } else { //we figure out which of the several XML files need to be downloaded. - for (NvdCveInfo entry : updates) { - if (MODIFIED.equals(entry.getId())) { - entry.setNeedsUpdate(true); - } else { - long currentTimestamp = 0; - try { - currentTimestamp = Long.parseLong(properties.getProperty(DatabaseProperties.LAST_UPDATED_BASE + entry.getId(), "0")); - } catch (NumberFormatException ex) { - LOGGER.debug("Error parsing '{}' '{}' from nvdcve.lastupdated", - DatabaseProperties.LAST_UPDATED_BASE, entry.getId(), ex); - } - if (currentTimestamp == entry.getTimestamp()) { - entry.setNeedsUpdate(false); - } - } - } - } - } catch (NumberFormatException ex) { - LOGGER.warn("An invalid schema version or timestamp exists in the data.properties file."); - LOGGER.debug("", ex); - } - } - return updates; - } - - /** - * Retrieves the timestamps from the NVD CVE meta data file. - * - * @return the timestamp from the currently published nvdcve downloads page - * @throws MalformedURLException thrown if the URL for the NVD CCE Meta data is incorrect. - * @throws DownloadFailedException thrown if there is an error downloading the nvd cve meta data file - * @throws InvalidDataException thrown if there is an exception parsing the timestamps - * @throws InvalidSettingException thrown if the settings are invalid - */ - private UpdateableNvdCve retrieveCurrentTimestampsFromWeb() - throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException { - - final UpdateableNvdCve updates = new UpdateableNvdCve(); - updates.add(MODIFIED, Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL), - Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL), - false); - - final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR); - final int end = Calendar.getInstance().get(Calendar.YEAR); - final String baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0); - final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2); - for (int i = start; i <= end; i++) { - updates.add(Integer.toString(i), String.format(baseUrl20, i), - String.format(baseUrl12, i), - true); - } - - return updates; - } - - /** - * Closes the CVE and CPE data stores. - */ - protected void closeDataStores() { - if (cveDB != null) { - try { - cveDB.close(); - } catch (Throwable ignore) { - LOGGER.trace("Error closing the cveDB", ignore); - } - } - } - - /** - * Opens the CVE and CPE data stores. - * - * @throws UpdateException thrown if a data store cannot be opened - */ - protected final void openDataStores() throws UpdateException { - if (cveDB != null) { - return; - } - try { - cveDB = new CveDB(); - cveDB.open(); - } catch (DatabaseException ex) { - closeDataStores(); - LOGGER.debug("Database Exception opening databases", ex); - throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details."); - } - } -} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateService.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateService.java index 8720b3539..96fbda0d1 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateService.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateService.java @@ -19,6 +19,7 @@ package org.owasp.dependencycheck.data.update; import java.util.Iterator; import java.util.ServiceLoader; +import org.owasp.dependencycheck.data.update.CachedWebDataSource; /** * The CachedWebDataSource Service Loader. This class loads all services that implement diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java new file mode 100644 index 000000000..2f7461881 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java @@ -0,0 +1,362 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update.cpe; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; +import org.owasp.dependencycheck.data.update.NvdCveUpdater; +import org.owasp.dependencycheck.data.update.exception.InvalidDataException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * A SAX Handler that will parse the CPE XML and load it into the databse. + * + * @author Jeremy Long + */ +public class CPEHandler extends DefaultHandler { + + /** + * The current CPE schema. + */ + private static final String CURRENT_SCHEMA_VERSION = "2.3"; + /** + * The text content of the node being processed. This can be used during the end element event. + */ + StringBuilder nodeText = null; + /** + * A reference to the current element. + */ + Element current = new Element(); + /** + * The logger. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(NvdCveUpdater.class); + /** + * The list of CPE values. + */ + List data = new ArrayList(); + + /** + * Returns the list of CPE values. + * + * @return the list of CPE values + */ + public List getData() { + return data; + } + + /** + * Handles the start element event + * + * @param uri the elements uri + * @param localName the local name + * @param qName the qualified name + * @param attributes the attributes + * @throws SAXException thrown if there is an exception processing the element + */ + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + nodeText = null; + current.setNode(qName); + if (current.isCpeItemNode()) { + String temp = attributes.getValue("deprecated"); + String value = attributes.getValue("name"); + boolean delete = (temp != null && temp.equalsIgnoreCase("true")); + if (!delete && value.startsWith("cpe:/a:") && value.length() > 7) { + try { + Cpe cpe = new Cpe(value); + data.add(cpe); + } catch (UnsupportedEncodingException ex) { + LOGGER.debug("Unable to parse the CPE", ex); + } catch (InvalidDataException ex) { + LOGGER.debug("CPE is not the correct format", ex); + } + } + } else if (current.isSchemaVersionNode()) { + nodeText = new StringBuilder(3); + } +// } else if (current.isTitleNode()) { +// //do nothing +// } else if (current.isMetaNode()) { +// //do nothing +// } else if (current.isTimestampNode()) { +// //do nothing +// } else if (current.isCpeListNode()) { +// //do nothing +// } else if (current.isNotesNode()) { +// //do nothing +// } else if (current.isNoteNode()) { +// //do nothing +// } else if (current.isCheckNode()) { +// //do nothing +// } else if (current.isGeneratorNode()) { +// //do nothing +// } else if (current.isProductNameNode()) { +// //do nothing +// } else if (current.isProductVersionNode()) { +// //do nothing + } + + /** + * Reads the characters in the current node. + * + * @param ch the char array + * @param start the start position of the data read + * @param length the length of the data read + * @throws SAXException thrown if there is an exception processing the characters + */ + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if (nodeText != null) { + nodeText.append(ch, start, length); + } + } + + /** + * Handles the end element event. Stores the CPE data in the Cve Database if the cpe item node is ending. + * + * @param uri the element's uri + * @param localName the local name + * @param qName the qualified name + * @throws SAXException thrown if there is an exception processing the element + */ + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + current.setNode(qName); + if (current.isSchemaVersionNode() && !CURRENT_SCHEMA_VERSION.equals(nodeText.toString())) { + throw new SAXException("ERROR: Unexpecgted CPE Schema Version, expected: " + + CURRENT_SCHEMA_VERSION + ", file is: " + nodeText); + + } +// } else if (current.isCpeItemNode()) { +// //do nothing +// } else if (current.isTitleNode()) { +// //do nothing +// } else if (current.isCpeListNode()) { +// //do nothing +// } else if (current.isMetaNode()) { +// //do nothing +// } else if (current.isNotesNode()) { +// //do nothing +// } else if (current.isNoteNode()) { +// //do nothing +// } else if (current.isCheckNode()) { +// //do nothing +// } else if (current.isGeneratorNode()) { +// //do nothing +// } else if (current.isProductNameNode()) { +// //do nothing +// } else if (current.isProductVersionNode()) { +// //do nothing +// else if (current.isTimestampNode()) { +// //do nothing +// } else { +// throw new SAXException("ERROR STATE: Unexpected qName '" + qName + "'"); +// } + } + + // + /** + * A simple class to maintain information about the current element while parsing the CPE XML. + */ + protected class Element { + + /** + * A node type in the CPE Schema 2.2 + */ + public static final String CPE_LIST = "cpe-list"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String CPE_ITEM = "cpe-item"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String TITLE = "title"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String NOTES = "notes"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String NOTE = "note"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String CHECK = "check"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String META = "meta:item-metadata"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String GENERATOR = "generator"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String PRODUCT_NAME = "product_name"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String PRODUCT_VERSION = "product_version"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String SCHEMA_VERSION = "schema_version"; + /** + * A node type in the CPE Schema 2.2 + */ + public static final String TIMESTAMP = "timestamp"; + private String node = null; + + /** + * Gets the value of node + * + * @return the value of node + */ + public String getNode() { + return this.node; + } + + /** + * Sets the value of node + * + * @param node new value of node + */ + public void setNode(String node) { + this.node = node; + } + + /** + * Checks if the handler is at the CPE_LIST node + * + * @return true or false + */ + public boolean isCpeListNode() { + return CPE_LIST.equals(node); + } + + /** + * Checks if the handler is at the CPE_ITEM node + * + * @return true or false + */ + public boolean isCpeItemNode() { + return CPE_ITEM.equals(node); + } + + /** + * Checks if the handler is at the TITLE node + * + * @return true or false + */ + public boolean isTitleNode() { + return TITLE.equals(node); + } + + /** + * Checks if the handler is at the NOTES node + * + * @return true or false + */ + public boolean isNotesNode() { + return NOTES.equals(node); + } + + /** + * Checks if the handler is at the NOTE node + * + * @return true or false + */ + public boolean isNoteNode() { + return NOTE.equals(node); + } + + /** + * Checks if the handler is at the CHECK node + * + * @return true or false + */ + public boolean isCheckNode() { + return CHECK.equals(node); + } + + /** + * Checks if the handler is at the META node + * + * @return true or false + */ + public boolean isMetaNode() { + return META.equals(node); + } + + /** + * Checks if the handler is at the GENERATOR node + * + * @return true or false + */ + public boolean isGeneratorNode() { + return GENERATOR.equals(node); + } + + /** + * Checks if the handler is at the PRODUCT_NAME node + * + * @return true or false + */ + public boolean isProductNameNode() { + return PRODUCT_NAME.equals(node); + } + + /** + * Checks if the handler is at the PRODUCT_VERSION node + * + * @return true or false + */ + public boolean isProductVersionNode() { + return PRODUCT_VERSION.equals(node); + } + + /** + * Checks if the handler is at the SCHEMA_VERSION node + * + * @return true or false + */ + public boolean isSchemaVersionNode() { + return SCHEMA_VERSION.equals(node); + } + + /** + * Checks if the handler is at the TIMESTAMP node + * + * @return true or false + */ + public boolean isTimestampNode() { + return TIMESTAMP.equals(node); + } + } + // +} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/Cpe.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/Cpe.java new file mode 100644 index 000000000..4309d2914 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/Cpe.java @@ -0,0 +1,114 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update.cpe; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import org.owasp.dependencycheck.data.update.exception.InvalidDataException; + +/** + * + * @author Jeremy Long + */ +public class Cpe { + + public Cpe(String value) throws UnsupportedEncodingException, InvalidDataException { + this.value = value; + final String[] data = value.substring(7).split(":"); + if (data.length >= 2) { + vendor = URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8"); + product = URLDecoder.decode(data[1].replace("+", "%2B"), "UTF-8"); + } else { + throw new InvalidDataException(String.format("CPE has an invalid format: %s", value)); + } + } + + /** + * The CPE identifier string (cpe:/a:vendor:product:version). + */ + private String value; + + /** + * Get the value of value. + * + * @return the value of value + */ + public String getValue() { + return value; + } + + /** + * Set the value of value. + * + * @param value new value of value + */ + public void setValue(String value) { + this.value = value; + } + /** + * The vendor portion of the identifier. + */ + private String vendor; + + /** + * Get the value of vendor + * + * @return the value of vendor + */ + public String getVendor() { + return vendor; + } + + /** + * Set the value of vendor + * + * @param vendor new value of vendor + */ + public void setVendor(String vendor) { + this.vendor = vendor; + } + + /** + * The product portion of the identifier. + */ + private String product; + + /** + * Get the value of product + * + * @return the value of product + */ + public String getProduct() { + return product; + } + + /** + * Set the value of product + * + * @param product new value of product + */ + public void setProduct(String product) { + this.product = product; + } + + @Override + public String toString() { + return value; + } + +} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/DownloadTask.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/DownloadTask.java similarity index 96% rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/DownloadTask.java rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/DownloadTask.java index 3365c179b..ed1ab22bc 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/DownloadTask.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/DownloadTask.java @@ -15,7 +15,7 @@ * * Copyright (c) 2013 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update.task; +package org.owasp.dependencycheck.data.update.nvd; import java.io.File; import java.io.FileInputStream; @@ -29,7 +29,6 @@ import java.util.concurrent.Future; import java.util.zip.GZIPInputStream; import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.data.nvdcve.CveDB; -import org.owasp.dependencycheck.data.update.NvdCveInfo; import org.owasp.dependencycheck.data.update.exception.UpdateException; import org.owasp.dependencycheck.utils.DownloadFailedException; import org.owasp.dependencycheck.utils.Downloader; @@ -55,8 +54,8 @@ public class DownloadTask implements Callable> { * @param nvdCveInfo the NVD CVE info * @param processor the processor service to submit the downloaded files to * @param cveDB the CVE DB to use to store the vulnerability data - * @param settings a reference to the global settings object; this is necessary so that when the thread is started - * the dependencies have a correct reference to the global settings. + * @param settings a reference to the global settings object; this is necessary so that when the thread is started the + * dependencies have a correct reference to the global settings. * @throws UpdateException thrown if temporary files could not be created */ public DownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB, Settings settings) throws UpdateException { @@ -248,8 +247,7 @@ public class DownloadTask implements Callable> { } /** - * Extracts the file contained in a gzip archive. The extracted file is placed in the exact same path as the file - * specified. + * Extracts the file contained in a gzip archive. The extracted file is placed in the exact same path as the file specified. * * @param file the archive file * @throws FileNotFoundException thrown if the file does not exist diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve12Handler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve12Handler.java similarity index 99% rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve12Handler.java rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve12Handler.java index 453f35b6b..26811ae7b 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve12Handler.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve12Handler.java @@ -15,7 +15,7 @@ * * Copyright (c) 2012 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update.xml; +package org.owasp.dependencycheck.data.update.nvd; import java.util.ArrayList; import java.util.HashMap; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve20Handler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve20Handler.java similarity index 99% rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve20Handler.java rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve20Handler.java index 1ecabd763..e2b60db7a 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve20Handler.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve20Handler.java @@ -15,7 +15,7 @@ * * Copyright (c) 2012 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update.xml; +package org.owasp.dependencycheck.data.update.nvd; import java.io.IOException; import java.util.List; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveInfo.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfo.java similarity index 98% rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveInfo.java rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfo.java index 45d366eb6..a143000a8 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveInfo.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfo.java @@ -15,7 +15,7 @@ * * Copyright (c) 2013 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update; +package org.owasp.dependencycheck.data.update.nvd; /** * A pojo that contains the Url and timestamp of the current NvdCve XML files. diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/ProcessTask.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java similarity index 97% rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/ProcessTask.java rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java index bb0583ad7..df8c52819 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/ProcessTask.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java @@ -15,7 +15,7 @@ * * Copyright (c) 2013 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update.task; +package org.owasp.dependencycheck.data.update.nvd; import java.io.File; import java.io.FileNotFoundException; @@ -31,8 +31,8 @@ import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; import org.owasp.dependencycheck.data.update.exception.UpdateException; -import org.owasp.dependencycheck.data.update.xml.NvdCve12Handler; -import org.owasp.dependencycheck.data.update.xml.NvdCve20Handler; +import org.owasp.dependencycheck.data.update.nvd.NvdCve12Handler; +import org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler; import org.owasp.dependencycheck.dependency.VulnerableSoftware; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateableNvdCve.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCve.java similarity index 95% rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateableNvdCve.java rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCve.java index 6fc48d0be..2b2cf22b3 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateableNvdCve.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCve.java @@ -15,7 +15,7 @@ * * Copyright (c) 2012 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update; +package org.owasp.dependencycheck.data.update.nvd; import java.net.MalformedURLException; import java.net.URL; @@ -27,8 +27,8 @@ import org.owasp.dependencycheck.utils.DownloadFailedException; import org.owasp.dependencycheck.utils.Downloader; /** - * Contains a collection of updateable NvdCveInfo objects. This is used to determine which files need to be downloaded - * and processed. + * Contains a collection of updateable NvdCveInfo objects. This is used to determine which files need to be downloaded and + * processed. * * @author Jeremy Long */ @@ -67,8 +67,7 @@ public class UpdateableNvdCve implements java.lang.Iterable, Iterato * * @param id the key for the item to be added * @param url the URL to download the item - * @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we - * need). + * @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we need). * @throws MalformedURLException thrown if the URL provided is invalid * @throws DownloadFailedException thrown if the download fails. */ @@ -81,8 +80,7 @@ public class UpdateableNvdCve implements java.lang.Iterable, Iterato * * @param id the key for the item to be added * @param url the URL to download the item - * @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we - * need). + * @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we need). * @param needsUpdate whether or not the data needs to be updated * @throws MalformedURLException thrown if the URL provided is invalid * @throws DownloadFailedException thrown if the download fails. @@ -175,7 +173,7 @@ public class UpdateableNvdCve implements java.lang.Iterable, Iterato * @param key the key to lookup the return value * @return the NvdCveInfo object stored using the specified key */ - NvdCveInfo get(String key) { + public NvdCveInfo get(String key) { return collection.get(key); } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/package-info.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java similarity index 89% rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/package-info.java rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java index 8dbc168c1..c1438046c 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/package-info.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java @@ -5,4 +5,4 @@ * extends Index). The Indexer creates a partial-unmarshalling SAX parser (implemented in the NvdCveXmlFilter) that extracts * VulnerabilityTypes (aka Entry) from the NVD CVE data file and stores these into a Lucene Index. */ -package org.owasp.dependencycheck.data.update.xml; +package org.owasp.dependencycheck.data.update.nvd; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/package-info.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/package-info.java deleted file mode 100644 index 0d9385edd..000000000 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * A collection of callable/runnable tasks used to speed up the update process. - */ -package org.owasp.dependencycheck.data.update.task; diff --git a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource index 73ca93754..915a3a73d 100644 --- a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource +++ b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource @@ -1,2 +1,3 @@ org.owasp.dependencycheck.data.update.NvdCveUpdater -org.owasp.dependencycheck.data.update.EngineVersionCheck \ No newline at end of file +org.owasp.dependencycheck.data.update.EngineVersionCheck +org.owasp.dependencycheck.data.update.CpeUpdater \ No newline at end of file diff --git a/dependency-check-core/src/main/resources/data/dbStatements.properties b/dependency-check-core/src/main/resources/data/dbStatements.properties index 5245a03f0..e612f259e 100644 --- a/dependency-check-core/src/main/resources/data/dbStatements.properties +++ b/dependency-check-core/src/main/resources/data/dbStatements.properties @@ -34,3 +34,6 @@ SELECT_PROPERTY=SELECT id, value FROM properties WHERE id = ? INSERT_PROPERTY=INSERT INTO properties (id, value) VALUES (?, ?) UPDATE_PROPERTY=UPDATE properties SET value = ? WHERE id = ? DELETE_PROPERTY=DELETE FROM properties WHERE id = ? + +DELETE_UNUSED_DICT_CPE=DELETE FROM cpeEntry WHERE dictionaryEntry=true AND id NOT IN (SELECT cpeEntryId FROM software) +ADD_DICT_CPE=MERGE INTO cpeEntry (cpe, vendor, product, dictionaryEntry) KEY(cpe) VALUES(?,?,?,true) diff --git a/dependency-check-core/src/main/resources/data/upgrade_2.9.sql b/dependency-check-core/src/main/resources/data/upgrade_2.9.sql new file mode 100644 index 000000000..175da176a --- /dev/null +++ b/dependency-check-core/src/main/resources/data/upgrade_2.9.sql @@ -0,0 +1,6 @@ + +ALTER TABLE cpeEntry ADD COLUMN IF NOT EXISTS dictionaryEntry BOOLEAN; +ALTER TABLE cpeEntry ALTER COLUMN dictionaryEntry SET DEFAULT FALSE; +UPDATE cpeEntry SET dictionaryEntry=false; + +UPDATE Properties SET value='3.0' WHERE ID='version'; \ No newline at end of file diff --git a/dependency-check-core/src/main/resources/dependencycheck.properties b/dependency-check-core/src/main/resources/dependencycheck.properties index 6bbba2235..1096e2d4d 100644 --- a/dependency-check-core/src/main/resources/dependencycheck.properties +++ b/dependency-check-core/src/main/resources/dependencycheck.properties @@ -17,8 +17,8 @@ engine.version.url=http://jeremylong.github.io/DependencyCheck/current.txt # below contains a %s then the data.directory will replace the %s. data.directory=[JAR]/data #if the filename has a %s it will be replaced with the current expected version -data.file_name=cve.%s.h2.db -data.version=2.9 +data.file_name=dc.h2.db +data.version=3.0 data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON; #data.connection_string=jdbc:mysql://localhost:3306/dependencycheck @@ -53,6 +53,8 @@ cve.url-1.2.base=https://nvd.nist.gov/download/nvdcve-%d.xml.gz cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz #cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml +cpe.validfordays=30 +cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.xml.gz # file type analyzer settings: analyzer.archive.enabled=true diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java index 242971ff4..76fe5cecd 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java @@ -45,7 +45,7 @@ public abstract class BaseDBTestCase extends BaseTest { public static void ensureDBExists() throws Exception { java.io.File dataPath = Settings.getDataDirectory(); - String fileName = String.format(Settings.getString(Settings.KEYS.DB_FILE_NAME), Settings.getString(Settings.KEYS.DB_VERSION)); + String fileName = Settings.getString(Settings.KEYS.DB_FILE_NAME); java.io.File dataFile = new File(dataPath, fileName); if (!dataPath.exists() || !dataFile.exists()) { dataPath.mkdirs(); diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/DatabasePropertiesIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/DatabasePropertiesIntegrationTest.java index e657f11ab..0d5d4112f 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/DatabasePropertiesIntegrationTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/DatabasePropertiesIntegrationTest.java @@ -21,7 +21,7 @@ import java.util.Properties; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Test; -import org.owasp.dependencycheck.data.update.NvdCveInfo; +import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo; /** * diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/BaseUpdaterTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/BaseUpdaterTest.java new file mode 100644 index 000000000..71d00d34e --- /dev/null +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/BaseUpdaterTest.java @@ -0,0 +1,98 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update; + +import org.junit.Test; +import static org.junit.Assert.*; +import org.owasp.dependencycheck.BaseTest; +import org.owasp.dependencycheck.data.nvdcve.CveDB; +import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; +import org.owasp.dependencycheck.data.update.exception.UpdateException; + +/** + * + * @author Jeremy Long + */ +public class BaseUpdaterTest extends BaseTest { + + /** + * Test of getCveDB method, of class BaseUpdater. + */ + @Test + public void testGetCveDB() { + BaseUpdater instance = new BaseUpdaterImpl(); + CveDB expResult = null; + CveDB result = instance.getCveDB(); + assertEquals(expResult, result); + } + + /** + * Test of getProperties method, of class BaseUpdater. + */ + @Test + public void testGetProperties() throws UpdateException { + BaseUpdater instance = null; + try { + instance = new BaseUpdaterImpl(); + instance.openDataStores(); + + DatabaseProperties result = instance.getProperties(); + assertTrue(result.getProperties().keySet().size() > 1); + } finally { + if (instance != null) { + instance.closeDataStores(); + } + } + } + + /** + * Test of closeDataStores method, of class BaseUpdater. + */ + @Test + public void testCloseDataStores() throws UpdateException { + BaseUpdater instance = null; + try { + instance = new BaseUpdaterImpl(); + instance.openDataStores(); + } finally { + if (instance != null) { + instance.closeDataStores(); + } + } + } + + /** + * Test of openDataStores method, of class BaseUpdater. + */ + @Test + public void testOpenDataStores() throws Exception { + BaseUpdater instance = null; + try { + instance = new BaseUpdaterImpl(); + instance.openDataStores(); + } finally { + if (instance != null) { + instance.closeDataStores(); + } + } + } + + public class BaseUpdaterImpl extends BaseUpdater { + } + +} diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/CpeUpdaterIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/CpeUpdaterIntegrationTest.java new file mode 100644 index 000000000..32879b12d --- /dev/null +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/CpeUpdaterIntegrationTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2015 OWASP. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.owasp.dependencycheck.data.update; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; +import org.owasp.dependencycheck.BaseTest; + +/** + * + * @author jeremy + */ +public class CpeUpdaterIntegrationTest extends BaseTest { + + /** + * Test of update method, of class CpeUpdater. + */ + @Test + public void testUpdate() throws Exception { + CpeUpdater instance = new CpeUpdater(); + instance.update(); + } + +} diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveUpdaterIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveUpdaterIntegrationTest.java index 3cf0554e7..8f43f1a09 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveUpdaterIntegrationTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveUpdaterIntegrationTest.java @@ -17,12 +17,13 @@ */ package org.owasp.dependencycheck.data.update; -import java.io.File; -import java.util.Calendar; -import org.junit.Before; +import java.net.MalformedURLException; +import static org.junit.Assert.assertNotNull; import org.junit.Test; import org.owasp.dependencycheck.BaseTest; -import org.owasp.dependencycheck.utils.Settings; +import org.owasp.dependencycheck.data.update.exception.UpdateException; +import org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve; +import org.owasp.dependencycheck.utils.DownloadFailedException; /** * @@ -30,39 +31,33 @@ import org.owasp.dependencycheck.utils.Settings; */ public class NvdCveUpdaterIntegrationTest extends BaseTest { - @Before - public void setUp() throws Exception { - int year = Calendar.getInstance().get(Calendar.YEAR); - if (year <= 2014) { - //File f = new File(NvdCveUpdaterIntegrationTest.class.getClassLoader().getResource("nvdcve-2.0-2014.xml").getPath()); - File f = BaseTest.getResourceAsFile(this, "nvdcve-2.0-2014.xml"); - String baseURL = f.toURI().toURL().toString(); - String modified12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-modified.xml"); - String modified20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-modified.xml"); - String full12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-%d.xml"); - String full20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-%d.xml"); -// cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml -// cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml -// cve.startyear=2014 -// cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml -// cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml - - Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, modified12); - Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, modified20); - Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, full12); - Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, full20); - Settings.setString(Settings.KEYS.CVE_START_YEAR, "2014"); - } else { - System.err.println("Consider updating the local data files to make the NvdCveUpdaterIntegrationTest perform faster"); - } + public NvdCveUpdater getUpdater() throws MalformedURLException, DownloadFailedException, UpdateException { + NvdCveUpdater instance = new NvdCveUpdater(); + return instance; } +// test removed as it is duplicative of the EngineIntegrationTest and the NvdCveUpdaterIntergraionTest +// /** +// * Test of update method, of class StandardUpdate. +// */ +// @Test +// public void testUpdate() throws Exception { +// StandardUpdate instance = getStandardUpdateTask(); +// instance.update(); +// //TODO make this an actual test +// } /** - * Test of update method, of class NvdCveUpdater. + * Test of updatesNeeded method, of class StandardUpdate. */ @Test - public void testUpdate() throws Exception { - NvdCveUpdater instance = new NvdCveUpdater(); - instance.update(); + public void testUpdatesNeeded() throws Exception { + NvdCveUpdater instance = getUpdater(); + try { + instance.openDataStores(); + UpdateableNvdCve result = instance.getUpdatesNeeded(); + assertNotNull(result); + } finally { + instance.closeDataStores(); + } } } diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/StandardUpdateIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/StandardUpdateIntegrationTest.java deleted file mode 100644 index 71516bbaf..000000000 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/StandardUpdateIntegrationTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2013 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.data.update; - -import java.net.MalformedURLException; -import static org.junit.Assert.assertNotNull; -import org.junit.Test; -import org.owasp.dependencycheck.BaseTest; -import org.owasp.dependencycheck.data.update.exception.UpdateException; -import org.owasp.dependencycheck.utils.DownloadFailedException; - -/** - * - * @author Jeremy Long - */ -public class StandardUpdateIntegrationTest extends BaseTest { - - public StandardUpdate getStandardUpdateTask() throws MalformedURLException, DownloadFailedException, UpdateException { - StandardUpdate instance = new StandardUpdate(); - return instance; - } - - /** - * Test of openDataStores method, of class StandardUpdate. - */ - @Test - public void testOpenDataStores() throws Exception { - StandardUpdate instance = getStandardUpdateTask(); - instance.openDataStores(); - instance.closeDataStores(); - } - -// test removed as it is duplicative of the EngineIntegrationTest and the NvdCveUpdaterIntergraionTest -// /** -// * Test of update method, of class StandardUpdate. -// */ -// @Test -// public void testUpdate() throws Exception { -// StandardUpdate instance = getStandardUpdateTask(); -// instance.update(); -// //TODO make this an actual test -// } - /** - * Test of updatesNeeded method, of class StandardUpdate. - */ - @Test - public void testUpdatesNeeded() throws Exception { - StandardUpdate instance = getStandardUpdateTask(); - UpdateableNvdCve result = instance.updatesNeeded(); - assertNotNull(result); - } -} diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/task/DownloadTaskTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/DownloadTaskTest.java similarity index 89% rename from dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/task/DownloadTaskTest.java rename to dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/DownloadTaskTest.java index bdc676e18..573f0739e 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/task/DownloadTaskTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/DownloadTaskTest.java @@ -15,8 +15,10 @@ * * Copyright (c) 2014 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update.task; +package org.owasp.dependencycheck.data.update.nvd; +import org.owasp.dependencycheck.data.update.nvd.ProcessTask; +import org.owasp.dependencycheck.data.update.nvd.DownloadTask; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import org.junit.After; @@ -26,7 +28,7 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.owasp.dependencycheck.data.nvdcve.CveDB; -import org.owasp.dependencycheck.data.update.NvdCveInfo; +import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo; import org.owasp.dependencycheck.utils.Settings; /** diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveInfoTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfoTest.java similarity index 95% rename from dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveInfoTest.java rename to dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfoTest.java index 84a5e54fc..81250cd52 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveInfoTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfoTest.java @@ -15,8 +15,9 @@ * * Copyright (c) 2013 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update; +package org.owasp.dependencycheck.data.update.nvd; +import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo; import static org.junit.Assert.assertEquals; import org.junit.Test; import org.owasp.dependencycheck.BaseTest; diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveUpdaterIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveUpdaterIntegrationTest.java new file mode 100644 index 000000000..d93fbce6b --- /dev/null +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveUpdaterIntegrationTest.java @@ -0,0 +1,69 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2013 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update.nvd; + +import java.io.File; +import java.util.Calendar; +import org.junit.Before; +import org.junit.Test; +import org.owasp.dependencycheck.BaseTest; +import org.owasp.dependencycheck.data.update.NvdCveUpdater; +import org.owasp.dependencycheck.utils.Settings; + +/** + * + * @author Jeremy Long + */ +public class NvdCveUpdaterIntegrationTest extends BaseTest { + + @Before + public void setUp() throws Exception { + int year = Calendar.getInstance().get(Calendar.YEAR); + if (year <= 2014) { + //File f = new File(NvdCveUpdaterIntegrationTest.class.getClassLoader().getResource("nvdcve-2.0-2014.xml").getPath()); + File f = BaseTest.getResourceAsFile(this, "nvdcve-2.0-2014.xml"); + String baseURL = f.toURI().toURL().toString(); + String modified12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-modified.xml"); + String modified20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-modified.xml"); + String full12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-%d.xml"); + String full20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-%d.xml"); +// cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml +// cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml +// cve.startyear=2014 +// cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml +// cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml + + Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, modified12); + Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, modified20); + Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, full12); + Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, full20); + Settings.setString(Settings.KEYS.CVE_START_YEAR, "2014"); + } else { + System.err.println("Consider updating the local data files to make the NvdCveUpdaterIntegrationTest perform faster"); + } + } + + /** + * Test of update method, of class NvdCveUpdater. + */ + @Test + public void testUpdate() throws Exception { + NvdCveUpdater instance = new NvdCveUpdater(); + instance.update(); + } +} diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_1_2_HandlerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_1_2_HandlerTest.java similarity index 94% rename from dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_1_2_HandlerTest.java rename to dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_1_2_HandlerTest.java index 2ab59b245..fa00e849f 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_1_2_HandlerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_1_2_HandlerTest.java @@ -15,8 +15,9 @@ * * Copyright (c) 2012 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update.xml; +package org.owasp.dependencycheck.data.update.nvd; +import org.owasp.dependencycheck.data.update.nvd.NvdCve12Handler; import java.io.File; import java.util.List; import java.util.Map; diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_2_0_HandlerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_2_0_HandlerTest.java similarity index 94% rename from dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_2_0_HandlerTest.java rename to dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_2_0_HandlerTest.java index 403bd6394..ea1c147ad 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_2_0_HandlerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_2_0_HandlerTest.java @@ -15,8 +15,9 @@ * * Copyright (c) 2012 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update.xml; +package org.owasp.dependencycheck.data.update.nvd; +import org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler; import java.io.File; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/UpdateableNvdCveTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCveTest.java similarity index 96% rename from dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/UpdateableNvdCveTest.java rename to dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCveTest.java index d8e979321..6aee2790e 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/UpdateableNvdCveTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCveTest.java @@ -15,8 +15,10 @@ * * Copyright (c) 2013 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update; +package org.owasp.dependencycheck.data.update.nvd; +import org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve; +import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; diff --git a/dependency-check-core/src/test/resources/dependencycheck.properties b/dependency-check-core/src/test/resources/dependencycheck.properties index 15f1ce0a8..541ce329d 100644 --- a/dependency-check-core/src/test/resources/dependencycheck.properties +++ b/dependency-check-core/src/test/resources/dependencycheck.properties @@ -19,8 +19,8 @@ data.directory=[JAR]/data # if the filename has a %s it will be replaced with the current expected version. For file # based databases the below filename will be added to the data directory above and then # if the connection string has a %s it will be replaced by the directory/filename path. -data.file_name=cve.%s.h2.db -data.version=2.9 +data.file_name=dc.h2.db +data.version=3.0 data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON; #data.connection_string=jdbc:mysql://localhost:3306/dependencycheck diff --git a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java index 0da632208..487ccc4a3 100644 --- a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java +++ b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java @@ -736,16 +736,15 @@ public final class Settings { * * @param connectionStringKey the property file key for the connection string * @param dbFileNameKey the settings key for the db filename - * @param dbVersionKey the settings key for the dbVersion * @return the connection string * @throws IOException thrown the data directory cannot be created * @throws InvalidSettingException thrown if there is an invalid setting */ - public static String getConnectionString(String connectionStringKey, String dbFileNameKey, String dbVersionKey) + public static String getConnectionString(String connectionStringKey, String dbFileNameKey) throws IOException, InvalidSettingException { final String connStr = Settings.getString(connectionStringKey); if (connStr == null) { - final String msg = String.format("Invalid properties file to get the connection string; '%s' must be defined.", + final String msg = String.format("Invalid properties file; data.connection_string is missing.", connectionStringKey); throw new InvalidSettingException(msg); } @@ -760,18 +759,6 @@ public final class Settings { dbFileNameKey); throw new InvalidSettingException(msg); } - if (fileName.contains("%s")) { - String version = null; - if (dbVersionKey != null) { - version = Settings.getString(dbVersionKey); - } - if (version == null) { - final String msg = String.format("Invalid properties file to get a file based connection string; '%s' must be defined.", - dbFileNameKey); - throw new InvalidSettingException(msg); - } - fileName = String.format(fileName, version); - } if (connStr.startsWith("jdbc:h2:file:") && fileName.endsWith(".h2.db")) { fileName = fileName.substring(0, fileName.length() - 6); } diff --git a/dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/SettingsTest.java b/dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/SettingsTest.java index 4c914d791..63caba59a 100644 --- a/dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/SettingsTest.java +++ b/dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/SettingsTest.java @@ -163,21 +163,15 @@ public class SettingsTest extends BaseTest { */ @Test public void testGetConnectionString() throws Exception { - String value = Settings.getConnectionString(Settings.KEYS.DB_CONNECTION_STRING, Settings.KEYS.DB_FILE_NAME, Settings.KEYS.DB_VERSION); + String value = Settings.getConnectionString(Settings.KEYS.DB_CONNECTION_STRING, Settings.KEYS.DB_FILE_NAME); Assert.assertNotNull(value); String msg = null; try { - value = Settings.getConnectionString(Settings.KEYS.DB_CONNECTION_STRING, Settings.KEYS.DB_FILE_NAME, null); + value = Settings.getConnectionString("invalidKey", null); } catch (InvalidSettingException e) { msg = e.getMessage(); } - Assert.assertNotNull(msg, msg); - try { - value = Settings.getConnectionString("invalidKey", null, null); - } catch (InvalidSettingException e) { - msg = e.getMessage(); - } - Assert.assertNotNull(msg, msg); + Assert.assertNotNull(msg); } /** diff --git a/dependency-check-utils/src/test/resources/dependencycheck.properties b/dependency-check-utils/src/test/resources/dependencycheck.properties index 2b9b6fcf2..447247e30 100644 --- a/dependency-check-utils/src/test/resources/dependencycheck.properties +++ b/dependency-check-utils/src/test/resources/dependencycheck.properties @@ -16,8 +16,8 @@ engine.version.url=http://jeremylong.github.io/DependencyCheck/current.txt # will not be used. The data.directory will be resolved and if the connection string # below contains a %s then the data.directory will replace the %s. data.directory=[JAR]/data -data.file_name=cve.%s.h2.db -data.version=2.9 +data.file_name=dc.h2.db +data.version=3.0 data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON; #data.connection_string=jdbc:h2:file:%s;AUTO_SERVER=TRUE;AUTOCOMMIT=ON; #data.connection_string=jdbc:mysql://localhost:3306/dependencycheck From db42da14d1a27e564bbb9eb38746c95f4dee7fc1 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 8 Jul 2015 06:31:08 -0400 Subject: [PATCH 31/41] updated documentation Former-commit-id: f4b200a38c5df345cd5714c4dbf624af57b40481 --- .../dependencycheck/data/update/cpe/package-info.java | 7 +++++++ .../dependencycheck/data/update/nvd/package-info.java | 6 +----- 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/package-info.java diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/package-info.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/package-info.java new file mode 100644 index 000000000..3176a4ea5 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/package-info.java @@ -0,0 +1,7 @@ +/** + * Contains classes used to parse the CPE XML file from NIST.

+ * + * These classes are not used as they add no value over the existing CPE data contained within the CVE data from the NVD. However, + * we may consider pulling the more descriptive data from the CPE data in the future. + */ +package org.owasp.dependencycheck.data.update.cpe; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java index c1438046c..7e061da07 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java @@ -1,8 +1,4 @@ /** - * Contains classes used to parse the NVD CVE XML file.

- * - * The basic use is that the Importer is called to import an NVD CVE file. The Importer instantiates an Indexer object (which - * extends Index). The Indexer creates a partial-unmarshalling SAX parser (implemented in the NvdCveXmlFilter) that extracts - * VulnerabilityTypes (aka Entry) from the NVD CVE data file and stores these into a Lucene Index. + * Contains classes used to download, parse, and load the NVD CVE data from NIST into the local database.

*/ package org.owasp.dependencycheck.data.update.nvd; From 70554d1158587e0936bd7847e210a1666ad0e692 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 8 Jul 2015 06:31:41 -0400 Subject: [PATCH 32/41] removed Cpe Updater as it will not currently be used Former-commit-id: 2d9d5a2082dc386697557943e46399c31633ffbc --- .../org.owasp.dependencycheck.data.update.CachedWebDataSource | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource index 915a3a73d..73ca93754 100644 --- a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource +++ b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource @@ -1,3 +1,2 @@ org.owasp.dependencycheck.data.update.NvdCveUpdater -org.owasp.dependencycheck.data.update.EngineVersionCheck -org.owasp.dependencycheck.data.update.CpeUpdater \ No newline at end of file +org.owasp.dependencycheck.data.update.EngineVersionCheck \ No newline at end of file From cae15a8d7aa32a88e477b7a1d42256b13bcb4e17 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 8 Jul 2015 06:32:20 -0400 Subject: [PATCH 33/41] updated javadoc Former-commit-id: 264561aed2a9e138d97c4f06c5e27df5b8acf7e9 --- .../org/owasp/dependencycheck/data/update/CpeUpdater.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java index 386b5afdd..637a4f2d9 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java @@ -26,7 +26,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.Date; import java.util.List; -import java.util.logging.Level; import java.util.zip.GZIPInputStream; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; @@ -45,6 +44,9 @@ import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; /** + * The CpeUpdater is designed to download the CPE data file from NIST and import the data into the database. However, as this + * currently adds no beneficial data, compared to what is in the CPE data contained in the CVE data files, this class is not + * currently used. The code is being kept as a future update may utilize more data from the CPE xml files. * * @author Jeremy Long */ From 3a06503b74ccc1a04746401a04fecf34a3a0246a Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 8 Jul 2015 06:32:52 -0400 Subject: [PATCH 34/41] commented out test case Former-commit-id: c62a28c8a39c42e6c458387c03445c86deb6454c --- .../data/update/CpeUpdaterIntegrationTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/CpeUpdaterIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/CpeUpdaterIntegrationTest.java index 32879b12d..7d08204bb 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/CpeUpdaterIntegrationTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/CpeUpdaterIntegrationTest.java @@ -34,8 +34,10 @@ public class CpeUpdaterIntegrationTest extends BaseTest { */ @Test public void testUpdate() throws Exception { - CpeUpdater instance = new CpeUpdater(); - instance.update(); + //commented out as the current code base does not utilize the CpeU[pdater. + +// CpeUpdater instance = new CpeUpdater(); +// instance.update(); } } From 055d34818a1d5128b23e090bef7e9ba5df88501e Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 8 Jul 2015 06:39:37 -0400 Subject: [PATCH 35/41] updated documentation to resolve issue #269 Former-commit-id: ae4668c9182f181f1c01c17e0737b892fe8078ba --- .../src/site/markdown/configuration.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/dependency-check-ant/src/site/markdown/configuration.md b/dependency-check-ant/src/site/markdown/configuration.md index a3025dde5..be106d0dd 100644 --- a/dependency-check-ant/src/site/markdown/configuration.md +++ b/dependency-check-ant/src/site/markdown/configuration.md @@ -23,20 +23,20 @@ Configuration ==================== The following properties can be set on the dependency-check-maven plugin. -Property | Description | Default Value ----------------------|------------------------------------|------------------ -autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true -updateOnly | If set to true only the update phase of dependency-check will be executed; no scan will be executed and no report will be generated. | false -externalReport | When using as a Site plugin this parameter sets whether or not the external report format should be used. | false -outputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target' -failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11 -format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML -suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../suppression.html) |   -proxyServer | The Proxy Server. |   -proxyPort | The Proxy Port. |   -proxyUsername | Defines the proxy user name. |   -proxyPassword | Defines the proxy password. |   -connectionTimeout | The URL Connection Timeout. |   +Property | Description | Default Value +----------------------|------------------------------------|------------------ +autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true +updateOnly | If set to true only the update phase of dependency-check will be executed; no scan will be executed and no report will be generated. | false +externalReport | When using as a Site plugin this parameter sets whether or not the external report format should be used. | false +reportOutputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target' +failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11 +reportFormat | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML +suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../suppression.html) |   +proxyServer | The Proxy Server. |   +proxyPort | The Proxy Port. |   +proxyUsername | Defines the proxy user name. |   +proxyPassword | Defines the proxy password. |   +connectionTimeout | The URL Connection Timeout. |   Analyzer Configuration ==================== From 5b2353e612c0dcbb25acb1453204a7e9e5e30517 Mon Sep 17 00:00:00 2001 From: ma wei Date: Thu, 9 Jul 2015 10:20:12 +0800 Subject: [PATCH 36/41] add license information for these gradle script files Former-commit-id: 1ecf5c52dc82e1fd55172385f303dc5022bad801 --- .../conf/publish/bintray.gradle | 18 ++++++++++++++++++ .../conf/publish/gradlePluginsPortal.gradle | 18 ++++++++++++++++++ .../conf/publish/local.gradle | 18 ++++++++++++++++++ .../conf/publish/maven.gradle | 18 ++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/dependency-check-gradle/conf/publish/bintray.gradle b/dependency-check-gradle/conf/publish/bintray.gradle index ba8f0ad6a..5dd533417 100644 --- a/dependency-check-gradle/conf/publish/bintray.gradle +++ b/dependency-check-gradle/conf/publish/bintray.gradle @@ -1,3 +1,21 @@ +/* + * This file is part of dependency-check-gradle. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 Wei Ma. All Rights Reserved. + */ + // publish to Bintray plugindev { pluginId = 'dependency.check' diff --git a/dependency-check-gradle/conf/publish/gradlePluginsPortal.gradle b/dependency-check-gradle/conf/publish/gradlePluginsPortal.gradle index 198ca9a76..a27ad77ba 100644 --- a/dependency-check-gradle/conf/publish/gradlePluginsPortal.gradle +++ b/dependency-check-gradle/conf/publish/gradlePluginsPortal.gradle @@ -1,3 +1,21 @@ +/* + * This file is part of dependency-check-gradle. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 Wei Ma. All Rights Reserved. + */ + // publish to gradle plugin portal pluginBundle { website = 'https://github.com/wmaintw/DependencyCheck' diff --git a/dependency-check-gradle/conf/publish/local.gradle b/dependency-check-gradle/conf/publish/local.gradle index e9b2f9d9a..00a6edd62 100644 --- a/dependency-check-gradle/conf/publish/local.gradle +++ b/dependency-check-gradle/conf/publish/local.gradle @@ -1,3 +1,21 @@ +/* + * This file is part of dependency-check-gradle. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 Wei Ma. All Rights Reserved. + */ + //Local debug use only uploadArchives { repositories { diff --git a/dependency-check-gradle/conf/publish/maven.gradle b/dependency-check-gradle/conf/publish/maven.gradle index ea83a7c5e..5f9787387 100644 --- a/dependency-check-gradle/conf/publish/maven.gradle +++ b/dependency-check-gradle/conf/publish/maven.gradle @@ -1,3 +1,21 @@ +/* + * This file is part of dependency-check-gradle. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 Wei Ma. All Rights Reserved. + */ + //upload to maven central uploadArchives { repositories { From 98a43606ce491e8503d542ca28f59e0a280fca98 Mon Sep 17 00:00:00 2001 From: Will Stranathan Date: Wed, 8 Jul 2015 22:19:52 -0400 Subject: [PATCH 37/41] Added homebrew instructions Former-commit-id: 05167f240768a8136e580544875454b3f2fdbdfe --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 5afe5f557..164bea864 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,12 @@ On Windows > bin/dependency-check.bat -h > bin/dependency-check.bat --app Testing --out . --scan [path to jar files to be scanned] ``` +On Mac with [Homebrew](http://brew.sh) +``` +$ brew update && brew install dependency-check +$ dependency-check -h +$ dependency-check --app Testing --out . --scan [path to jar files to be scanned] +``` ### Maven Plugin From bf3fe6404a7dda7cce2b88de6292fe897f4fe1eb Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Thu, 9 Jul 2015 06:18:30 -0400 Subject: [PATCH 38/41] reverted changes as a schema upgrade is not needed at this time Former-commit-id: 22671cb1c7e2e6db26f704f12b5fb86100586221 --- .../src/main/resources/data/upgrade_2.9.sql | 9 +++++---- .../src/main/resources/dependencycheck.properties | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/dependency-check-core/src/main/resources/data/upgrade_2.9.sql b/dependency-check-core/src/main/resources/data/upgrade_2.9.sql index 175da176a..6c2c3382d 100644 --- a/dependency-check-core/src/main/resources/data/upgrade_2.9.sql +++ b/dependency-check-core/src/main/resources/data/upgrade_2.9.sql @@ -1,6 +1,7 @@ -ALTER TABLE cpeEntry ADD COLUMN IF NOT EXISTS dictionaryEntry BOOLEAN; -ALTER TABLE cpeEntry ALTER COLUMN dictionaryEntry SET DEFAULT FALSE; -UPDATE cpeEntry SET dictionaryEntry=false; +--the following is not currently used. +--ALTER TABLE cpeEntry ADD COLUMN IF NOT EXISTS dictionaryEntry BOOLEAN; +--ALTER TABLE cpeEntry ALTER COLUMN dictionaryEntry SET DEFAULT FALSE; +--UPDATE cpeEntry SET dictionaryEntry=false; -UPDATE Properties SET value='3.0' WHERE ID='version'; \ No newline at end of file +--UPDATE Properties SET value='3.0' WHERE ID='version'; \ No newline at end of file diff --git a/dependency-check-core/src/main/resources/dependencycheck.properties b/dependency-check-core/src/main/resources/dependencycheck.properties index 1096e2d4d..89f4c5e83 100644 --- a/dependency-check-core/src/main/resources/dependencycheck.properties +++ b/dependency-check-core/src/main/resources/dependencycheck.properties @@ -18,7 +18,7 @@ engine.version.url=http://jeremylong.github.io/DependencyCheck/current.txt data.directory=[JAR]/data #if the filename has a %s it will be replaced with the current expected version data.file_name=dc.h2.db -data.version=3.0 +data.version=2.9 data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON; #data.connection_string=jdbc:mysql://localhost:3306/dependencycheck From 54094ebc215b54e5b86f73091cdd9d1a53529862 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Thu, 9 Jul 2015 06:37:29 -0400 Subject: [PATCH 39/41] removed unfinished JavaScriptAnalyzer Former-commit-id: 9d7d7e82da91cea21ea87b8d933093e738571ba2 --- .../analyzer/JavaScriptAnalyzer.java | 135 - .../analyzer/JavaScriptAnalyzerTest.java | 115 - .../src/test/resources/jquery-1.10.2.js | 9789 ----------------- .../src/test/resources/jquery-1.10.2.min.js | 6 - .../src/test/resources/jquery-1.6.2.min.js | 18 - .../src/test/resources/jquery.prettyPhoto.js | 911 -- .../src/test/resources/jquery.prettyPhoto_.js | 905 -- 7 files changed, 11879 deletions(-) delete mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzer.java delete mode 100644 dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzerTest.java delete mode 100644 dependency-check-core/src/test/resources/jquery-1.10.2.js delete mode 100644 dependency-check-core/src/test/resources/jquery-1.10.2.min.js delete mode 100644 dependency-check-core/src/test/resources/jquery-1.6.2.min.js delete mode 100644 dependency-check-core/src/test/resources/jquery.prettyPhoto.js delete mode 100644 dependency-check-core/src/test/resources/jquery.prettyPhoto_.js diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzer.java deleted file mode 100644 index 6af9c3a8c..000000000 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzer.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2014 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.analyzer; - -import org.owasp.dependencycheck.Engine; -import org.owasp.dependencycheck.analyzer.exception.AnalysisException; -import org.owasp.dependencycheck.dependency.Dependency; -import org.owasp.dependencycheck.utils.FileFilterBuilder; -import org.owasp.dependencycheck.utils.Settings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.*; -import java.util.regex.Pattern; - -/** - * - * Used to analyze a JavaScript file to gather information to aid in identification of a CPE identifier. - * - * @author Jeremy Long - */ -public class JavaScriptAnalyzer extends AbstractFileTypeAnalyzer { - - /** - * The logger. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(JavaScriptAnalyzer.class); - - // - /** - * The name of the analyzer. - */ - private static final String ANALYZER_NAME = "JavaScript Analyzer"; - /** - * The phase that this analyzer is intended to run in. - */ - private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION; - /** - * The set of file extensions supported by this analyzer. - */ - private static final String EXTENSIONS = "js"; - - private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build(); - - @Override - protected FileFilter getFileFilter() { - return FILTER; - } - - /** - * Returns the name of the analyzer. - * - * @return the name of the analyzer. - */ - @Override - public String getName() { - return ANALYZER_NAME; - } - - /** - * Returns the phase that the analyzer is intended to run in. - * - * @return the phase that the analyzer is intended to run in. - */ - @Override - public AnalysisPhase getAnalysisPhase() { - return ANALYSIS_PHASE; - } - // - /** - * Returns the key used in the properties file to reference the analyzer's enabled property. - * - * @return the analyzer's enabled property setting key - */ - @Override - protected String getAnalyzerEnabledSettingKey() { - return Settings.KEYS.ANALYZER_JAVASCRIPT_ENABLED; - } - - /** - * Loads a specified JavaScript file and collects information from the copyright information contained within. - * - * @param dependency the dependency to analyze. - * @param engine the engine that is scanning the dependencies - * @throws AnalysisException is thrown if there is an error reading the JavaScript file. - */ - @Override - public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException { - BufferedReader fin = null; - try { - // /\*([^\*][^/]|[\r\n\f])+?\*/ - final Pattern extractComments = Pattern.compile("(/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/)|(//.*)", Pattern.MULTILINE); - File file = dependency.getActualFile(); - fin = new BufferedReader(new FileReader(file)); - StringBuilder sb = new StringBuilder(2000); - String text; - while ((text = fin.readLine()) != null) { - sb.append(text); - } - } catch (FileNotFoundException ex) { - final String msg = String.format("Dependency file not found: '%s'", dependency.getActualFilePath()); - throw new AnalysisException(msg, ex); - } catch (IOException ex) { - LOGGER.error("", ex); - } finally { - if (fin != null) { - try { - fin.close(); - } catch (IOException ex) { - LOGGER.trace("", ex); - } - } - } - } - - @Override - protected void initializeFileTypeAnalyzer() throws Exception { - - } -} diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzerTest.java deleted file mode 100644 index fb1169039..000000000 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzerTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2014 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.analyzer; - -import org.junit.Test; -import org.owasp.dependencycheck.BaseTest; -import org.owasp.dependencycheck.Engine; -import org.owasp.dependencycheck.dependency.Dependency; - -import java.io.File; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * - * @author Jeremy Long - */ -public class JavaScriptAnalyzerTest extends BaseTest { - - /** - * Test of getSupportedExtensions method, of class JavaScriptAnalyzer. - */ - @Test - public void testAcceptSupportedExtensions() throws Exception { - JavaScriptAnalyzer instance = new JavaScriptAnalyzer(); - instance.initialize(); - instance.setEnabled(true); - String name = "test.js"; - assertTrue(name, instance.accept(new File(name))); - } - - /** - * Test of getName method, of class JavaScriptAnalyzer. - */ - @Test - public void testGetName() { - System.out.println("getName"); - JavaScriptAnalyzer instance = new JavaScriptAnalyzer(); - String expResult = "JavaScript Analyzer"; - String result = instance.getName(); - assertEquals(expResult, result); - } - - /** - * Test of getAnalysisPhase method, of class JavaScriptAnalyzer. - */ - @Test - public void testGetAnalysisPhase() { - JavaScriptAnalyzer instance = new JavaScriptAnalyzer(); - AnalysisPhase expResult = AnalysisPhase.INFORMATION_COLLECTION; - AnalysisPhase result = instance.getAnalysisPhase(); - assertEquals(expResult, result); - } - - /** - * Test of analyze method, of class JavaScriptAnalyzer. - */ - @Test - public void testAnalyze() throws Exception { - //File jq6 = new File(this.getClass().getClassLoader().getResource("jquery-1.6.2.min.js").getPath()); - File jq6 = BaseTest.getResourceAsFile(this, "jquery-1.6.2.min.js"); - //File jq10 = new File(this.getClass().getClassLoader().getResource("jquery-1.10.2.js").getPath()); - File jq10 = BaseTest.getResourceAsFile(this, "jquery-1.10.2.js"); - //File jq10min = new File(this.getClass().getClassLoader().getResource("jquery-1.10.2.min.js").getPath()); - File jq10min = BaseTest.getResourceAsFile(this, "jquery-1.10.2.min.js"); - Dependency depJQ6 = new Dependency(jq6); - Dependency depJQ10 = new Dependency(jq10); - Dependency depJQ10min = new Dependency(jq10min); - Engine engine = null; - JavaScriptAnalyzer instance = new JavaScriptAnalyzer(); - -// assertTrue(depJQ6.getEvidence().size() == 0); -// assertTrue(depJQ10.getEvidence().size() == 0); -// assertTrue(depJQ10min.getEvidence().size() == 0); -// -// instance.analyze(depJQ6, engine); -// instance.analyze(depJQ10, engine); -// instance.analyze(depJQ10min, engine); -// //TODO improve the assertions -// assertTrue(depJQ6.getEvidence().size() > 0); -// assertTrue(depJQ10.getEvidence().size() > 0); -// assertTrue(depJQ10min.getEvidence().size() > 0); - } - - /** - * Test of initialize method, of class JavaScriptAnalyzer. - */ - @Test - public void testInitialize() throws Exception { - } - - /** - * Test of close method, of class JavaScriptAnalyzer. - */ - @Test - public void testClose() throws Exception { - - } -} diff --git a/dependency-check-core/src/test/resources/jquery-1.10.2.js b/dependency-check-core/src/test/resources/jquery-1.10.2.js deleted file mode 100644 index c5c648255..000000000 --- a/dependency-check-core/src/test/resources/jquery-1.10.2.js +++ /dev/null @@ -1,9789 +0,0 @@ -/*! - * jQuery JavaScript Library v1.10.2 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2013-07-03T13:48Z - */ -(function( window, undefined ) { - -// Can't do this because several apps including ASP.NET trace -// the stack via arguments.caller.callee and Firefox dies if -// you try to trace through "use strict" call chains. (#13335) -// Support: Firefox 18+ -//"use strict"; -var - // The deferred used on DOM ready - readyList, - - // A central reference to the root jQuery(document) - rootjQuery, - - // Support: IE<10 - // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined` - core_strundefined = typeof undefined, - - // Use the correct document accordingly with window argument (sandbox) - location = window.location, - document = window.document, - docElem = document.documentElement, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // [[Class]] -> type pairs - class2type = {}, - - // List of deleted data cache ids, so we can reuse them - core_deletedIds = [], - - core_version = "1.10.2", - - // Save a reference to some core methods - core_concat = core_deletedIds.concat, - core_push = core_deletedIds.push, - core_slice = core_deletedIds.slice, - core_indexOf = core_deletedIds.indexOf, - core_toString = class2type.toString, - core_hasOwn = class2type.hasOwnProperty, - core_trim = core_version.trim, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Used for matching numbers - core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, - - // Used for splitting on whitespace - core_rnotwhite = /\S+/g, - - // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, - rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }, - - // The ready event handler - completed = function( event ) { - - // readyState === "complete" is good enough for us to call the dom ready in oldIE - if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { - detach(); - jQuery.ready(); - } - }, - // Clean-up method for dom ready events - detach = function() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", completed, false ); - window.removeEventListener( "load", completed, false ); - - } else { - document.detachEvent( "onreadystatechange", completed ); - window.detachEvent( "onload", completed ); - } - }; - -jQuery.fn = jQuery.prototype = { - // The current version of jQuery being used - jquery: core_version, - - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - - // scripts is true for back-compat - jQuery.merge( this, jQuery.parseHTML( - match[1], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return core_slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - ret.context = this.context; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; - }, - - slice: function() { - return this.pushStack( core_slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: core_push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var src, copyIsArray, copy, name, options, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), - - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - /* jshint eqeqeq: false */ - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - if ( obj == null ) { - return String( obj ); - } - return typeof obj === "object" || typeof obj === "function" ? - class2type[ core_toString.call(obj) ] || "object" : - typeof obj; - }, - - isPlainObject: function( obj ) { - var key; - - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !core_hasOwn.call(obj, "constructor") && - !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Support: IE<9 - // Handle iteration over inherited properties before own properties. - if ( jQuery.support.ownLast ) { - for ( key in obj ) { - return core_hasOwn.call( obj, key ); - } - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - for ( key in obj ) {} - - return key === undefined || core_hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - // data: string of html - // context (optional): If specified, the fragment will be created in this context, defaults to document - // keepScripts (optional): If true, will include scripts passed in the html string - parseHTML: function( data, context, keepScripts ) { - if ( !data || typeof data !== "string" ) { - return null; - } - if ( typeof context === "boolean" ) { - keepScripts = context; - context = false; - } - context = context || document; - - var parsed = rsingleTag.exec( data ), - scripts = !keepScripts && []; - - // Single tag - if ( parsed ) { - return [ context.createElement( parsed[1] ) ]; - } - - parsed = jQuery.buildFragment( [ data ], context, scripts ); - if ( scripts ) { - jQuery( scripts ).remove(); - } - return jQuery.merge( [], parsed.childNodes ); - }, - - parseJSON: function( data ) { - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - if ( data === null ) { - return data; - } - - if ( typeof data === "string" ) { - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - if ( data ) { - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - } - } - } - - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - if ( !data || typeof data !== "string" ) { - return null; - } - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && jQuery.trim( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var value, - i = 0, - length = obj.length, - isArray = isArraylike( obj ); - - if ( args ) { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } - } - - return obj; - }, - - // Use native String.trim function wherever possible - trim: core_trim && !core_trim.call("\uFEFF\xA0") ? - function( text ) { - return text == null ? - "" : - core_trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArraylike( Object(arr) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - core_push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( core_indexOf ) { - return core_indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var l = second.length, - i = first.length, - j = 0; - - if ( typeof l === "number" ) { - for ( ; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var retVal, - ret = [], - i = 0, - length = elems.length; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, - i = 0, - length = elems.length, - isArray = isArraylike( elems ), - ret = []; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return core_concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var args, proxy, tmp; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = core_slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - length = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < length; i++ ) { - fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); - } - } - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations. - // Note: this method belongs to the css module but it's needed here for the support module. - // If support gets modularized, this method should be moved back to the css module. - swap: function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; - } -}); - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the browser event has already occurred. - // we once tried to use readyState "interactive" here, but it caused issues like the one - // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 - if ( document.readyState === "complete" ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", completed ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", completed ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // detach all dom ready events - detach(); - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -function isArraylike( obj ) { - var length = obj.length, - type = jQuery.type( obj ); - - if ( jQuery.isWindow( obj ) ) { - return false; - } - - if ( obj.nodeType === 1 && length ) { - return true; - } - - return type === "array" || type !== "function" && - ( length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj ); -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); -/*! - * Sizzle CSS Selector Engine v1.10.2 - * http://sizzlejs.com/ - * - * Copyright 2013 jQuery Foundation, Inc. and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2013-07-03 - */ -(function( window, undefined ) { - -var i, - support, - cachedruns, - Expr, - getText, - isXML, - compile, - outermostContext, - sortInput, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + -(new Date()), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - hasDuplicate = false, - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - return 0; - }, - - // General-purpose constants - strundefined = typeof undefined, - MAX_NEGATIVE = 1 << 31, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf if we can't use a native one - indexOf = arr.indexOf || function( elem ) { - var i = 0, - len = this.length; - for ( ; i < len; i++ ) { - if ( this[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + - "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", - - // Prefer arguments quoted, - // then not containing pseudos/brackets, - // then attribute selectors/non-parenthetical expressions, - // then anything else - // These preferences are here to reduce the number of selectors - // needing tokenize in the PSEUDO preFilter - pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rsibling = new RegExp( whitespace + "*[+~]" ), - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rescape = /'|\\/g, - - // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - // BMP codepoint - high < 0 ? - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }; - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var match, elem, m, nodeType, - // QSA vars - i, groups, old, nid, newContext, newSelector; - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - - context = context || document; - results = results || []; - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { - return []; - } - - if ( documentIsHTML && !seed ) { - - // Shortcuts - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // QSA path - if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - nid = old = expando; - newContext = context; - newSelector = nodeType === 9 && selector; - - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - groups = tokenize( selector ); - - if ( (old = context.getAttribute("id")) ) { - nid = old.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - nid = "[id='" + nid + "'] "; - - i = groups.length; - while ( i-- ) { - groups[i] = nid + toSelector( groups[i] ); - } - newContext = rsibling.test( selector ) && context.parentNode || context; - newSelector = groups.join(","); - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {Function(string, Object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key += " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created div and expects a boolean result - */ -function assert( fn ) { - var div = document.createElement("div"); - - try { - return !!fn( div ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( div.parentNode ) { - div.parentNode.removeChild( div ); - } - // release memory in IE - div = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = attrs.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - ( ~b.sourceIndex || MAX_NEGATIVE ) - - ( ~a.sourceIndex || MAX_NEGATIVE ); - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Detect xml - * @param {Element|Object} elem An element or a document - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var doc = node ? node.ownerDocument || node : preferredDoc, - parent = doc.defaultView; - - // If no document and documentElement is available, return - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Set our document - document = doc; - docElem = doc.documentElement; - - // Support tests - documentIsHTML = !isXML( doc ); - - // Support: IE>8 - // If iframe document is assigned to "document" variable and if iframe has been reloaded, - // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 - // IE6-8 do not support the defaultView property so parent will be undefined - if ( parent && parent.attachEvent && parent !== parent.top ) { - parent.attachEvent( "onbeforeunload", function() { - setDocument(); - }); - } - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) - support.attributes = assert(function( div ) { - div.className = "i"; - return !div.getAttribute("className"); - }); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( div ) { - div.appendChild( doc.createComment("") ); - return !div.getElementsByTagName("*").length; - }); - - // Check if getElementsByClassName can be trusted - support.getElementsByClassName = assert(function( div ) { - div.innerHTML = "
"; - - // Support: Safari<4 - // Catch class over-caching - div.firstChild.className = "i"; - // Support: Opera<10 - // Catch gEBCN failure to find non-leading classes - return div.getElementsByClassName("i").length === 2; - }); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function( div ) { - docElem.appendChild( div ).id = expando; - return !doc.getElementsByName || !doc.getElementsByName( expando ).length; - }); - - // ID find and filter - if ( support.getById ) { - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== strundefined && documentIsHTML ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - }; - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - } else { - // Support: IE6/7 - // getElementById is not reliable as a find shortcut - delete Expr.find["ID"]; - - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - } - - // Tag - Expr.find["TAG"] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var elem, - tmp = [], - i = 0, - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See http://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // http://bugs.jquery.com/ticket/12359 - div.innerHTML = ""; - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - - // Support: Opera 10-12/IE8 - // ^= $= *= and empty values - // Should not select anything - // Support: Windows 8 Native Apps - // The type attribute is restricted during .innerHTML assignment - var input = doc.createElement("input"); - input.setAttribute( "type", "hidden" ); - div.appendChild( input ).setAttribute( "t", "" ); - - if ( div.querySelectorAll("[t^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - div.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( div, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - /* Contains - ---------------------------------------------------------------------- */ - - // Element contains another - // Purposefully does not implement inclusive descendent - // As in, an element does not contain itself - contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = docElem.compareDocumentPosition ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b ); - - if ( compare ) { - // Disconnected nodes - if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === doc || contains(preferredDoc, a) ) { - return -1; - } - if ( b === doc || contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } - - // Not directly comparable, sort on existence of method - return a.compareDocumentPosition ? -1 : 1; - } : - function( a, b ) { - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Parentless nodes are either documents or disconnected - } else if ( !aup || !bup ) { - return a === doc ? -1 : - b === doc ? 1 : - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return doc; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - if ( support.matchesSelector && documentIsHTML && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, document, null, [elem] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val === undefined ? - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? - val.value : - null : - val; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - for ( ; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (see #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[5] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[3] && match[4] !== undefined ) { - match[2] = match[4]; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { return true; } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, outerCache, node, diff, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - // Seek `elem` from a previously-cached index - outerCache = parent[ expando ] || (parent[ expando ] = {}); - cache = outerCache[ type ] || []; - nodeIndex = cache[0] === dirruns && cache[1]; - diff = cache[0] === dirruns && cache[2]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - outerCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - // Use previously-cached element index if available - } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { - diff = cache[1]; - - // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) - } else { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { - // Cache the index of each encountered element - if ( useCache ) { - (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf.call( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), - // not comment, processing instructions, or others - // Thanks to Diego Perini for the nodeName shortcut - // Greater than "@" means alpha characters (specifically not starting with "#" or "?") - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -function tokenize( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( tokens = [] ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push({ - value: matched, - type: type, - matches: match - }); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -} - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - checkNonElements = base && dir === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var data, cache, outerCache, - dirkey = dirruns + " " + doneName; - - // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { - if ( (data = cache[1]) === true || data === cachedruns ) { - return data === true; - } - } else { - cache = outerCache[ dir ] = [ dirkey ]; - cache[1] = matcher( elem, context, xml ) || cachedruns; - if ( cache[1] === true ) { - return true; - } - } - } - } - } - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf.call( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - // A counter to specify which element is currently being matched - var matcherCachedRuns = 0, - bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, expandContext ) { - var elem, j, matcher, - setMatched = [], - matchedCount = 0, - i = "0", - unmatched = seed && [], - outermost = expandContext != null, - contextBackup = outermostContext, - // We must always have either seed elements or context - elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); - - if ( outermost ) { - outermostContext = context !== document && context; - cachedruns = matcherCachedRuns; - } - - // Add elements passing elementMatchers directly to results - // Keep `i` a string if there are no elements so `matchedCount` will be "00" below - for ( ; (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context, xml ) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - cachedruns = ++matcherCachedRuns; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // Apply set filters to unmatched elements - matchedCount += i; - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !group ) { - group = tokenize( selector ); - } - i = group.length; - while ( i-- ) { - cached = matcherFromTokens( group[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - } - return cached; -}; - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function select( selector, context, results, seed ) { - var i, tokens, token, type, find, - match = tokenize( selector ); - - if ( !seed ) { - // Try to minimize operations if there is only one group - if ( match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - support.getById && context.nodeType === 9 && documentIsHTML && - Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - } - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && context.parentNode || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - } - - // Compile and execute a filtering function - // Provide `match` to avoid retokenization if we modified the selector above - compile( selector, match )( - seed, - context, - !documentIsHTML, - results, - rsibling.test( selector ) - ); - return results; -} - -// One-time assignments - -// Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Support: Chrome<14 -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( div1 ) { - // Should return 1, but returns 4 (following) - return div1.compareDocumentPosition( document.createElement("div") ) & 1; -}); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( div ) { - div.innerHTML = ""; - return div.firstChild.getAttribute("href") === "#" ; -}) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - }); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( div ) { - div.innerHTML = ""; - div.firstChild.setAttribute( "value", "" ); - return div.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - }); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( div ) { - return div.getAttribute("disabled") == null; -}) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return (val = elem.getAttributeNode( name )) && val.specified ? - val.value : - elem[ name ] === true ? name.toLowerCase() : null; - } - }); -} - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})( window ); -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // First callback to fire (used internally by add and fireWith) - firingStart, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - var type = jQuery.type( arg ); - if ( type === "function" ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && type !== "string" ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); - }, - // Remove all callbacks from the list - empty: function() { - list = []; - firingLength = 0; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( list && ( !fired || stack ) ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var action = tuple[ 0 ], - fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ](function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); - } - }); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] - deferred[ tuple[0] ] = function() { - deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); - return this; - }; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = core_slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; - if( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); -jQuery.support = (function( support ) { - - var all, a, input, select, fragment, opt, eventName, isSupported, i, - div = document.createElement("div"); - - // Setup - div.setAttribute( "className", "t" ); - div.innerHTML = "
a"; - - // Finish early in limited (non-browser) environments - all = div.getElementsByTagName("*") || []; - a = div.getElementsByTagName("a")[ 0 ]; - if ( !a || !a.style || !all.length ) { - return support; - } - - // First batch of tests - select = document.createElement("select"); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName("input")[ 0 ]; - - a.style.cssText = "top:1px;float:left;opacity:.5"; - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - support.getSetAttribute = div.className !== "t"; - - // IE strips leading whitespace when .innerHTML is used - support.leadingWhitespace = div.firstChild.nodeType === 3; - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - support.tbody = !div.getElementsByTagName("tbody").length; - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - support.htmlSerialize = !!div.getElementsByTagName("link").length; - - // Get the style information from getAttribute - // (IE uses .cssText instead) - support.style = /top/.test( a.getAttribute("style") ); - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - support.hrefNormalized = a.getAttribute("href") === "/a"; - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - support.opacity = /^0.5/.test( a.style.opacity ); - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - support.cssFloat = !!a.style.cssFloat; - - // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) - support.checkOn = !!input.value; - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - support.optSelected = opt.selected; - - // Tests for enctype support on a form (#6743) - support.enctype = !!document.createElement("form").enctype; - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - support.html5Clone = document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>"; - - // Will be defined later - support.inlineBlockNeedsLayout = false; - support.shrinkWrapBlocks = false; - support.pixelPosition = false; - support.deleteExpando = true; - support.noCloneEvent = true; - support.reliableMarginRight = true; - support.boxSizingReliable = true; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Support: IE<9 - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - // Check if we can trust getAttribute("value") - input = document.createElement("input"); - input.setAttribute( "value", "" ); - support.input = input.getAttribute( "value" ) === ""; - - // Check if an input maintains its value after becoming a radio - input.value = "t"; - input.setAttribute( "type", "radio" ); - support.radioValue = input.value === "t"; - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "checked", "t" ); - input.setAttribute( "name", "t" ); - - fragment = document.createDocumentFragment(); - fragment.appendChild( input ); - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE<9 - // Opera does not clone events (and typeof div.attachEvent === undefined). - // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() - if ( div.attachEvent ) { - div.attachEvent( "onclick", function() { - support.noCloneEvent = false; - }); - - div.cloneNode( true ).click(); - } - - // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event) - // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) - for ( i in { submit: true, change: true, focusin: true }) { - div.setAttribute( eventName = "on" + i, "t" ); - - support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false; - } - - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - // Support: IE<9 - // Iteration over object's inherited properties before its own. - for ( i in jQuery( support ) ) { - break; - } - support.ownLast = i !== "0"; - - // Run tests that need a body at doc ready - jQuery(function() { - var container, marginDiv, tds, - divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - container = document.createElement("div"); - container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; - - body.appendChild( container ).appendChild( div ); - - // Support: IE8 - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - div.innerHTML = "
t
"; - tds = div.getElementsByTagName("td"); - tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Support: IE8 - // Check if empty table cells still have offsetWidth/Height - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check box-sizing and margin behavior. - div.innerHTML = ""; - div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; - - // Workaround failing boxSizing test due to offsetWidth returning wrong value - // with some non-1 values of body zoom, ticket #13543 - jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() { - support.boxSizing = div.offsetWidth === 4; - }); - - // Use window.getComputedStyle because jsdom on node.js will break without it. - if ( window.getComputedStyle ) { - support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; - support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. (#3333) - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - marginDiv = div.appendChild( document.createElement("div") ); - marginDiv.style.cssText = div.style.cssText = divReset; - marginDiv.style.marginRight = marginDiv.style.width = "0"; - div.style.width = "1px"; - - support.reliableMarginRight = - !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); - } - - if ( typeof div.style.zoom !== core_strundefined ) { - // Support: IE<8 - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - div.innerHTML = ""; - div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Support: IE6 - // Check if elements with layout shrink-wrap their children - div.style.display = "block"; - div.innerHTML = "
"; - div.firstChild.style.width = "5px"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - - if ( support.inlineBlockNeedsLayout ) { - // Prevent IE 6 from affecting layout for positioned elements #11048 - // Prevent IE from shrinking the body in IE 7 mode #12869 - // Support: IE<8 - body.style.zoom = 1; - } - } - - body.removeChild( container ); - - // Null elements to avoid leaks in IE - container = div = tds = marginDiv = null; - }); - - // Null elements to avoid leaks in IE - all = select = fragment = opt = a = input = null; - - return support; -})({}); - -var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, - rmultiDash = /([A-Z])/g; - -function internalData( elem, name, data, pvt /* Internal Use Only */ ){ - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var ret, thisCache, - internalKey = jQuery.expando, - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - id = elem[ internalKey ] = core_deletedIds.pop() || jQuery.guid++; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - // Avoid exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( typeof name === "string" ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; -} - -function internalRemoveData( elem, name, pvt ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, i, - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } else { - // If "name" is an array of keys... - // When data is initially created, via ("key", "val") signature, - // keys will be converted to camelCase. - // Since there is no way to tell _how_ a key was added, remove - // both plain key and camelCase key. #12786 - // This will only penalize the array argument path. - name = name.concat( jQuery.map( name, jQuery.camelCase ) ); - } - - i = name.length; - while ( i-- ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - /* jshint eqeqeq: false */ - } else if ( jQuery.support.deleteExpando || cache != cache.window ) { - /* jshint eqeqeq: true */ - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } -} - -jQuery.extend({ - cache: {}, - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "applet": true, - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data ) { - return internalData( elem, name, data ); - }, - - removeData: function( elem, name ) { - return internalRemoveData( elem, name ); - }, - - // For internal use only. - _data: function( elem, name, data ) { - return internalData( elem, name, data, true ); - }, - - _removeData: function( elem, name ) { - return internalRemoveData( elem, name, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - // Do not set data on non-element because it will not be cleared (#8335). - if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) { - return false; - } - - var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; - - // nodes accept data unless otherwise specified; rejection can be conditional - return !noData || noData !== true && elem.getAttribute("classid") === noData; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var attrs, name, - data = null, - i = 0, - elem = this[0]; - - // Special expections of .data basically thwart jQuery.access, - // so implement the relevant behavior ourselves - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attrs = elem.attributes; - for ( ; i < attrs.length; i++ ) { - name = attrs[i].name; - - if ( name.indexOf("data-") === 0 ) { - name = jQuery.camelCase( name.slice(5) ); - - dataAttr( elem, name, data[ name ] ); - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - return arguments.length > 1 ? - - // Sets one value - this.each(function() { - jQuery.data( this, key, value ); - }) : - - // Gets one value - // Try to fetch any internally stored data first - elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null; - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery._removeData( elem, type + "queue" ); - jQuery._removeData( elem, key ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while( i-- ) { - tmp = jQuery._data( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var nodeHook, boolHook, - rclass = /[\t\r\n\f]/g, - rreturn = /\r/g, - rfocusable = /^(?:input|select|textarea|button|object)$/i, - rclickable = /^(?:a|area)$/i, - ruseDefault = /^(?:checked|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute, - getSetInput = jQuery.support.input; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classes, elem, cur, clazz, j, - i = 0, - len = this.length, - proceed = typeof value === "string" && value; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call( this, j, this.className ) ); - }); - } - - if ( proceed ) { - // The disjunction here is for better compressibility (see removeClass) - classes = ( value || "" ).match( core_rnotwhite ) || []; - - for ( ; i < len; i++ ) { - elem = this[ i ]; - cur = elem.nodeType === 1 && ( elem.className ? - ( " " + elem.className + " " ).replace( rclass, " " ) : - " " - ); - - if ( cur ) { - j = 0; - while ( (clazz = classes[j++]) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - elem.className = jQuery.trim( cur ); - - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, clazz, j, - i = 0, - len = this.length, - proceed = arguments.length === 0 || typeof value === "string" && value; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call( this, j, this.className ) ); - }); - } - if ( proceed ) { - classes = ( value || "" ).match( core_rnotwhite ) || []; - - for ( ; i < len; i++ ) { - elem = this[ i ]; - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( elem.className ? - ( " " + elem.className + " " ).replace( rclass, " " ) : - "" - ); - - if ( cur ) { - j = 0; - while ( (clazz = classes[j++]) ) { - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - elem.className = value ? jQuery.trim( cur ) : ""; - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value; - - if ( typeof stateVal === "boolean" && type === "string" ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - classNames = value.match( core_rnotwhite ) || []; - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( type === core_strundefined || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // If the element has a class name or if we're passed "false", - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var ret, hooks, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // Use proper attribute retrieval(#6932, #12072) - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - elem.text; - } - }, - select: { - get: function( elem ) { - var value, option, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one" || index < 0, - values = one ? null : [], - max = one ? index + 1 : options.length, - i = index < 0 ? - max : - one ? index : 0; - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // oldIE doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - // Don't return options that are disabled or in a disabled optgroup - ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && - ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) { - optionSet = true; - } - } - - // force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - attr: function( elem, name, value ) { - var hooks, ret, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === core_strundefined ) { - return jQuery.prop( elem, name, value ); - } - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - - } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, value + "" ); - return value; - } - - } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var name, propName, - i = 0, - attrNames = value && value.match( core_rnotwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( (name = attrNames[i++]) ) { - propName = jQuery.propFix[ name ] || name; - - // Boolean attributes get special treatment (#10870) - if ( jQuery.expr.match.bool.test( name ) ) { - // Set corresponding property to false - if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { - elem[ propName ] = false; - // Support: IE<9 - // Also clear defaultChecked/defaultSelected (if appropriate) - } else { - elem[ jQuery.camelCase( "default-" + name ) ] = - elem[ propName ] = false; - } - - // See #9699 for explanation of this approach (setting first, then removal) - } else { - jQuery.attr( elem, name, "" ); - } - - elem.removeAttribute( getSetAttribute ? name : propName ); - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to default in case type is set after value during creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ? - ret : - ( elem[ name ] = value ); - - } else { - return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ? - ret : - elem[ name ]; - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - return tabindex ? - parseInt( tabindex, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - -1; - } - } - } -}); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { - // IE<8 needs the *property* name - elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); - - // Use defaultChecked and defaultSelected for oldIE - } else { - elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; - } - - return name; - } -}; -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { - var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr; - - jQuery.expr.attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ? - function( elem, name, isXML ) { - var fn = jQuery.expr.attrHandle[ name ], - ret = isXML ? - undefined : - /* jshint eqeqeq: false */ - (jQuery.expr.attrHandle[ name ] = undefined) != - getter( elem, name, isXML ) ? - - name.toLowerCase() : - null; - jQuery.expr.attrHandle[ name ] = fn; - return ret; - } : - function( elem, name, isXML ) { - return isXML ? - undefined : - elem[ jQuery.camelCase( "default-" + name ) ] ? - name.toLowerCase() : - null; - }; -}); - -// fix oldIE attroperties -if ( !getSetInput || !getSetAttribute ) { - jQuery.attrHooks.value = { - set: function( elem, value, name ) { - if ( jQuery.nodeName( elem, "input" ) ) { - // Does not return so that setAttribute is also used - elem.defaultValue = value; - } else { - // Use nodeHook if defined (#1954); otherwise setAttribute is fine - return nodeHook && nodeHook.set( elem, value, name ); - } - } - }; -} - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = { - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - elem.setAttributeNode( - (ret = elem.ownerDocument.createAttribute( name )) - ); - } - - ret.value = value += ""; - - // Break association with cloned elements by also using setAttribute (#9646) - return name === "value" || value === elem.getAttribute( name ) ? - value : - undefined; - } - }; - jQuery.expr.attrHandle.id = jQuery.expr.attrHandle.name = jQuery.expr.attrHandle.coords = - // Some attributes are constructed with empty-string values when not defined - function( elem, name, isXML ) { - var ret; - return isXML ? - undefined : - (ret = elem.getAttributeNode( name )) && ret.value !== "" ? - ret.value : - null; - }; - jQuery.valHooks.button = { - get: function( elem, name ) { - var ret = elem.getAttributeNode( name ); - return ret && ret.specified ? - ret.value : - undefined; - }, - set: nodeHook.set - }; - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - set: function( elem, value, name ) { - nodeHook.set( elem, value === "" ? false : value, name ); - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }; - }); -} - - -// Some attributes require a special call on IE -// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !jQuery.support.hrefNormalized ) { - // href/src property should get the full normalized URL (#10299/#12915) - jQuery.each([ "href", "src" ], function( i, name ) { - jQuery.propHooks[ name ] = { - get: function( elem ) { - return elem.getAttribute( name, 4 ); - } - }; - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Note: IE uppercases css property names, but if we were to .toLowerCase() - // .cssText, that would destroy case senstitivity in URL's, like in "background" - return elem.style.cssText || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = value + "" ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }; -} - -jQuery.each([ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -}); - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }; - if ( !jQuery.support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - // Support: Webkit - // "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - }; - } -}); -var rformElems = /^(?:input|select|textarea)$/i, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - var tmp, events, t, handleObjIn, - special, eventHandle, handleObj, - handlers, type, namespaces, origType, - elemData = jQuery._data( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !(events = elemData.events) ) { - events = elemData.events = {}; - } - if ( !(eventHandle = elemData.handle) ) { - eventHandle = elemData.handle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( core_rnotwhite ) || [""]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !(handlers = events[ type ]) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - var j, handleObj, tmp, - origCount, t, events, - special, handlers, type, - namespaces, origType, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( core_rnotwhite ) || [""]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery._removeData( elem, "events" ); - } - }, - - trigger: function( event, data, elem, onlyHandlers ) { - var handle, ontype, cur, - bubbleType, special, tmp, i, - eventPath = [ elem || document ], - type = core_hasOwn.call( event, "type" ) ? event.type : event, - namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf(".") >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf(":") < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join("."); - event.namespace_re = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === (elem.ownerDocument || document) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && - jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - try { - elem[ type ](); - } catch ( e ) { - // IE<9 dies on focus/blur to hidden element (#1486,#12518) - // only reproducible on winXP IE8 native, not IE9 in IE8 mode - } - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event ); - - var i, ret, handleObj, matched, j, - handlerQueue = [], - args = core_slice.call( arguments ), - handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( (event.result = ret) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var sel, handleObj, matches, i, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - // Black-hole SVG instance trees (#13180) - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { - - /* jshint eqeqeq: false */ - for ( ; cur != this; cur = cur.parentNode || this ) { - /* jshint eqeqeq: true */ - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { - matches = []; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matches[ sel ] === undefined ) { - matches[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) >= 0 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matches[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, handlers: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( delegateCount < handlers.length ) { - handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); - } - - return handlerQueue; - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, copy, - type = event.type, - originalEvent = event, - fixHook = this.fixHooks[ type ]; - - if ( !fixHook ) { - this.fixHooks[ type ] = fixHook = - rmouseEvent.test( type ) ? this.mouseHooks : - rkeyEvent.test( type ) ? this.keyHooks : - {}; - } - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = new jQuery.Event( originalEvent ); - - i = copy.length; - while ( i-- ) { - prop = copy[ i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Support: IE<9 - // Fix target property (#1925) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Support: Chrome 23+, Safari? - // Target should not be a text node (#504, #13143) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // Support: IE<9 - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) - event.metaKey = !!event.metaKey; - - return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var body, eventDoc, doc, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - special: { - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - focus: { - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - try { - this.focus(); - return false; - } catch ( e ) { - // Support: IE<9 - // If we error on focus to hidden element (#1486, #12518), - // let .trigger() run the handlers - } - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - click: { - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { - this.click(); - return false; - } - }, - - // For cross-browser consistency, don't fire native .click() on links - _default: function( event ) { - return jQuery.nodeName( event.target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Even when returnValue equals to undefined Firefox will still show alert - if ( event.result !== undefined ) { - event.originalEvent.returnValue = event.result; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === core_strundefined ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - if ( !e ) { - return; - } - - // If preventDefault exists, run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // Support: IE - // Otherwise set the returnValue property of the original event to false - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - if ( !e ) { - return; - } - // If stopPropagation exists, run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - - // Support: IE - // Set the cancelBubble property of the original event to true - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - } -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "submitBubbles" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "submitBubbles", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "changeBubbles", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return !rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var type, origFn; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - var elem = this[0]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -}); -var isSimple = /^.[^:#\[\.,]*$/, - rparentsprev = /^(?:parents|prev(?:Until|All))/, - rneedsContext = jQuery.expr.match.needsContext, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var i, - ret = [], - self = this, - len = self.length; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }) ); - } - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - // Needed because $( selector, context ) becomes $( context ).find( selector ) - ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); - ret.selector = this.selector ? this.selector + " " + selector : selector; - return ret; - }, - - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector || [], true) ); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector || [], false) ); - }, - - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - ret = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { - // Always skip document fragments - if ( cur.nodeType < 11 && (pos ? - pos.index(cur) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector(cur, selectors)) ) { - - cur = ret.push( cur ); - break; - } - } - } - - return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( jQuery.unique(all) ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - if ( this.length > 1 ) { - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - ret = jQuery.unique( ret ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - } - - return this.pushStack( ret ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 && elem.nodeType === 1 ? - jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : - jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - })); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - /* jshint -W018 */ - return !!qualifier.call( elem, i, elem ) !== not; - }); - - } - - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - }); - - } - - if ( typeof qualifier === "string" ) { - if ( isSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, elements, not ); - } - - qualifier = jQuery.filter( qualifier, elements ); - } - - return jQuery.grep( elements, function( elem ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; - }); -} -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /\s*$/g, - - // We have to close these tags to support XHTML (#13200) - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
", "
" ], - area: [ 1, "", "" ], - param: [ 1, "", "" ], - thead: [ 1, "", "
" ], - tr: [ 2, "", "
" ], - col: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, - // unless wrapped in a div with non-breaking characters in front of it. - _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -jQuery.fn.extend({ - text: function( value ) { - return jQuery.access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - append: function() { - return this.domManip( arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip( arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - }); - }, - - before: function() { - return this.domManip( arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - }); - }, - - after: function() { - return this.domManip( arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - }); - }, - - // keepData is for internal use only--do not document - remove: function( selector, keepData ) { - var elem, - elems = selector ? jQuery.filter( selector, this ) : this, - i = 0; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem ) ); - } - - if ( elem.parentNode ) { - if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { - setGlobalEval( getAll( elem, "script" ) ); - } - elem.parentNode.removeChild( elem ); - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - - // If this is a select, ensure that it displays empty (#12336) - // Support: IE<9 - if ( elem.options && jQuery.nodeName( elem, "select" ) ) { - elem.options.length = 0; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function () { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return jQuery.access( this, function( value ) { - var elem = this[0] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var - // Snapshot the DOM in case .domManip sweeps something relevant into its fragment - args = jQuery.map( this, function( elem ) { - return [ elem.nextSibling, elem.parentNode ]; - }), - i = 0; - - // Make the changes, replacing each context element with the new content - this.domManip( arguments, function( elem ) { - var next = args[ i++ ], - parent = args[ i++ ]; - - if ( parent ) { - // Don't use the snapshot next if it has moved (#13810) - if ( next && next.parentNode !== parent ) { - next = this.nextSibling; - } - jQuery( this ).remove(); - parent.insertBefore( elem, next ); - } - // Allow new content to include elements from the context set - }, true ); - - // Force removal if there was no new content (e.g., from empty arguments) - return i ? this : this.remove(); - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, callback, allowIntersection ) { - - // Flatten any nested arrays - args = core_concat.apply( [], args ); - - var first, node, hasScripts, - scripts, doc, fragment, - i = 0, - l = this.length, - set = this, - iNoClone = l - 1, - value = args[0], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) { - return this.each(function( index ) { - var self = set.eq( index ); - if ( isFunction ) { - args[0] = value.call( this, index, self.html() ); - } - self.domManip( args, callback, allowIntersection ); - }); - } - - if ( l ) { - fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( this[i], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { - - if ( node.src ) { - // Hope ajax is available... - jQuery._evalUrl( node.src ); - } else { - jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - } - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - } - } - - return this; - } -}); - -// Support: IE<8 -// Manipulating tables requires a tbody -function manipulationTarget( elem, content ) { - return jQuery.nodeName( elem, "table" ) && - jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ? - - elem.getElementsByTagName("tbody")[0] || - elem.appendChild( elem.ownerDocument.createElement("tbody") ) : - elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - if ( match ) { - elem.type = match[1]; - } else { - elem.removeAttribute("type"); - } - return elem; -} - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var elem, - i = 0; - for ( ; (elem = elems[i]) != null; i++ ) { - jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); - } -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function fixCloneNodeIssues( src, dest ) { - var nodeName, e, data; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - nodeName = dest.nodeName.toLowerCase(); - - // IE6-8 copies events bound via attachEvent when using cloneNode. - if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) { - data = jQuery._data( dest ); - - for ( e in data.events ) { - jQuery.removeEvent( dest, e, data.handle ); - } - - // Event data gets referenced instead of copied if the expando gets copied too - dest.removeAttribute( jQuery.expando ); - } - - // IE blanks contents when cloning scripts, and tries to evaluate newly-set text - if ( nodeName === "script" && dest.text !== src.text ) { - disableScript( dest ).text = src.text; - restoreScript( dest ); - - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - } else if ( nodeName === "object" ) { - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.defaultSelected = dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone(true); - jQuery( insert[i] )[ original ]( elems ); - - // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() - core_push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -}); - -function getAll( context, tag ) { - var elems, elem, - i = 0, - found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) : - typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) : - undefined; - - if ( !found ) { - for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { - if ( !tag || jQuery.nodeName( elem, tag ) ) { - found.push( elem ); - } else { - jQuery.merge( found, getAll( elem, tag ) ); - } - } - } - - return tag === undefined || tag && jQuery.nodeName( context, tag ) ? - jQuery.merge( [ context ], found ) : - found; -} - -// Used in buildFragment, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( manipulation_rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var destElements, node, clone, i, srcElements, - inPage = jQuery.contains( elem.ownerDocument, elem ); - - if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - - // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - // Fix all IE cloning issues - for ( i = 0; (node = srcElements[i]) != null; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - fixCloneNodeIssues( node, destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0; (node = srcElements[i]) != null; i++ ) { - cloneCopyEvent( node, destElements[i] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - destElements = srcElements = node = null; - - // Return the cloned set - return clone; - }, - - buildFragment: function( elems, context, scripts, selection ) { - var j, elem, contains, - tmp, tag, tbody, wrap, - l = elems.length, - - // Ensure a safe fragment - safe = createSafeFragment( context ), - - nodes = [], - i = 0; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || safe.appendChild( context.createElement("div") ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - - tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; - - // Descend through wrappers to the right content - j = wrap[0]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Manually add leading whitespace removed by IE - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); - } - - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { - - // String was a , *may* have spurious - elem = tag === "table" && !rtbody.test( elem ) ? - tmp.firstChild : - - // String was a bare or - wrap[1] === "
" && !rtbody.test( elem ) ? - tmp : - 0; - - j = elem && elem.childNodes.length; - while ( j-- ) { - if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { - elem.removeChild( tbody ); - } - } - } - - jQuery.merge( nodes, tmp.childNodes ); - - // Fix #12392 for WebKit and IE > 9 - tmp.textContent = ""; - - // Fix #12392 for oldIE - while ( tmp.firstChild ) { - tmp.removeChild( tmp.firstChild ); - } - - // Remember the top-level container for proper cleanup - tmp = safe.lastChild; - } - } - } - - // Fix #11356: Clear elements from fragment - if ( tmp ) { - safe.removeChild( tmp ); - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !jQuery.support.appendChecked ) { - jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); - } - - i = 0; - while ( (elem = nodes[ i++ ]) ) { - - // #4087 - If origin and destination elements are the same, and this is - // that element, do not do anything - if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( safe.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( (elem = tmp[ j++ ]) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - tmp = null; - - return safe; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var elem, type, id, data, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = jQuery.support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( typeof elem.removeAttribute !== core_strundefined ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - core_deletedIds.push( id ); - } - } - } - } - }, - - _evalUrl: function( url ) { - return jQuery.ajax({ - url: url, - type: "GET", - dataType: "script", - async: false, - global: false, - "throws": true - }); - } -}); -jQuery.fn.extend({ - wrapAll: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapAll( html.call(this, i) ); - }); - } - - if ( this[0] ) { - // The elements to wrap the target around - var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); - - if ( this[0].parentNode ) { - wrap.insertBefore( this[0] ); - } - - wrap.map(function() { - var elem = this; - - while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { - elem = elem.firstChild; - } - - return elem; - }).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapInner( html.call(this, i) ); - }); - } - - return this.each(function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - }); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each(function(i) { - jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); - }); - }, - - unwrap: function() { - return this.parent().each(function() { - if ( !jQuery.nodeName( this, "body" ) ) { - jQuery( this ).replaceWith( this.childNodes ); - } - }).end(); - } -}); -var iframe, getStyles, curCSS, - ralpha = /alpha\([^)]*\)/i, - ropacity = /opacity\s*=\s*([^)]*)/, - rposition = /^(top|right|bottom|left)$/, - // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" - // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rmargin = /^margin/, - rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), - rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), - rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), - elemdisplay = { BODY: "block" }, - - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400 - }, - - cssExpand = [ "Top", "Right", "Bottom", "Left" ], - cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; - -// return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { - - // shortcut for names that are not vendor prefixed - if ( name in style ) { - return name; - } - - // check for vendor prefixed names - var capName = name.charAt(0).toUpperCase() + name.slice(1), - origName = name, - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in style ) { - return name; - } - } - - return origName; -} - -function isHidden( elem, el ) { - // isHidden might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); -} - -function showHide( elements, show ) { - var display, elem, hidden, - values = [], - index = 0, - length = elements.length; - - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - values[ index ] = jQuery._data( elem, "olddisplay" ); - display = elem.style.display; - if ( show ) { - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !values[ index ] && display === "none" ) { - elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( elem.style.display === "" && isHidden( elem ) ) { - values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); - } - } else { - - if ( !values[ index ] ) { - hidden = isHidden( elem ); - - if ( display && display !== "none" || !hidden ) { - jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); - } - } - } - } - - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( index = 0; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - if ( !show || elem.style.display === "none" || elem.style.display === "" ) { - elem.style.display = show ? values[ index ] || "" : "none"; - } - } - - return elements; -} - -jQuery.fn.extend({ - css: function( name, value ) { - return jQuery.access( this, function( elem, name, value ) { - var len, styles, - map = {}, - i = 0; - - if ( jQuery.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - }, - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each(function() { - if ( isHidden( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - }); - } -}); - -jQuery.extend({ - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - "columnCount": true, - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - // normalize float css property - "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - style = elem.style; - - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && (ret = rrelNum.exec( value )) ) { - value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); - // Fixes bug #9237 - type = "number"; - } - - // Make sure that NaN and null values aren't set. See: #7116 - if ( value == null || type === "number" && isNaN( value ) ) { - return; - } - - // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( type === "number" && !jQuery.cssNumber[ origName ] ) { - value += "px"; - } - - // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, - // but it would mean to define eight (for every problematic property) identical functions - if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - - // Wrapped to prevent IE from throwing errors when 'invalid' values are provided - // Fixes bug #5509 - try { - style[ name ] = value; - } catch(e) {} - } - - } else { - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var num, val, hooks, - origName = jQuery.camelCase( name ); - - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - //convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Return, converting to number if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; - } - return val; - } -}); - -// NOTE: we've included the "window" in window.getComputedStyle -// because jsdom on node.js will break without it. -if ( window.getComputedStyle ) { - getStyles = function( elem ) { - return window.getComputedStyle( elem, null ); - }; - - curCSS = function( elem, name, _computed ) { - var width, minWidth, maxWidth, - computed = _computed || getStyles( elem ), - - // getPropertyValue is only needed for .css('filter') in IE9, see #12537 - ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, - style = elem.style; - - if ( computed ) { - - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right - // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels - // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values - if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret; - }; -} else if ( document.documentElement.currentStyle ) { - getStyles = function( elem ) { - return elem.currentStyle; - }; - - curCSS = function( elem, name, _computed ) { - var left, rs, rsLeft, - computed = _computed || getStyles( elem ), - ret = computed ? computed[ name ] : undefined, - style = elem.style; - - // Avoid setting ret to empty string here - // so we don't default to auto - if ( ret == null && style && style[ name ] ) { - ret = style[ name ]; - } - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - // but not position css attributes, as those are proportional to the parent element instead - // and we can't measure the parent instead because it might trigger a "stacking dolls" problem - if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { - - // Remember the original values - left = style.left; - rs = elem.runtimeStyle; - rsLeft = rs && rs.left; - - // Put in the new values to get a computed value out - if ( rsLeft ) { - rs.left = elem.currentStyle.left; - } - style.left = name === "fontSize" ? "1em" : ret; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - if ( rsLeft ) { - rs.left = rsLeft; - } - } - - return ret === "" ? "auto" : ret; - }; -} - -function setPositiveNumber( elem, value, subtract ) { - var matches = rnumsplit.exec( value ); - return matches ? - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { - var i = extra === ( isBorderBox ? "border" : "content" ) ? - // If we already have the right measurement, avoid augmentation - 4 : - // Otherwise initialize for horizontal or vertical properties - name === "width" ? 1 : 0, - - val = 0; - - for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); - } - - if ( isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // at this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } else { - // at this point, extra isn't content, so add padding - val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // at this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with offset property, which is equivalent to the border-box value - var valueIsBorderBox = true, - val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - styles = getStyles( elem ), - isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // some non-html elements return undefined for offsetWidth, so check for null/undefined - // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 - // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 - if ( val <= 0 || val == null ) { - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name, styles ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // we need the check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - } - - // use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles - ) - ) + "px"; -} - -// Try to determine the default display value of an element -function css_defaultDisplay( nodeName ) { - var doc = document, - display = elemdisplay[ nodeName ]; - - if ( !display ) { - display = actualDisplay( nodeName, doc ); - - // If the simple way fails, read from inside an iframe - if ( display === "none" || !display ) { - // Use the already-created iframe if possible - iframe = ( iframe || - jQuery("', - inline_markup: '
{content}
', - custom_markup: '', - social_tools: '' /* html or false to disable */ - }, pp_settings); - - // Global variables accessible only by prettyPhoto - var matchedObjects = this, percentBased = false, pp_dimensions, pp_open, - - // prettyPhoto container specific - pp_contentHeight, pp_contentWidth, pp_containerHeight, pp_containerWidth, - - // Window size - windowHeight = $(window).height(), windowWidth = $(window).width(), - - // Global elements - pp_slideshow; - - doresize = true, scroll_pos = _get_scroll(); - - // Window/Keyboard events - $(window).unbind('resize.prettyphoto').bind('resize.prettyphoto',function(){ _center_overlay(); _resize_overlay(); }); - - if(pp_settings.keyboard_shortcuts) { - $(document).unbind('keydown.prettyphoto').bind('keydown.prettyphoto',function(e){ - if(typeof $pp_pic_holder != 'undefined'){ - if($pp_pic_holder.is(':visible')){ - switch(e.keyCode){ - case 37: - $.prettyPhoto.changePage('previous'); - e.preventDefault(); - break; - case 39: - $.prettyPhoto.changePage('next'); - e.preventDefault(); - break; - case 27: - if(!settings.modal) - $.prettyPhoto.close(); - e.preventDefault(); - break; - }; - // return false; - }; - }; - }); - }; - - /** - * Initialize prettyPhoto. - */ - $.prettyPhoto.initialize = function() { - - settings = pp_settings; - - if(settings.theme == 'pp_default') settings.horizontal_padding = 16; - - // Find out if the picture is part of a set - theRel = $(this).attr(settings.hook); - galleryRegExp = /\[(?:.*)\]/; - isSet = (galleryRegExp.exec(theRel)) ? true : false; - - // Put the SRCs, TITLEs, ALTs into an array. - pp_images = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return $(n).attr('href'); }) : $.makeArray($(this).attr('href')); - pp_titles = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return ($(n).find('img').attr('alt')) ? $(n).find('img').attr('alt') : ""; }) : $.makeArray($(this).find('img').attr('alt')); - pp_descriptions = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return ($(n).attr('title')) ? $(n).attr('title') : ""; }) : $.makeArray($(this).attr('title')); - - if(pp_images.length > settings.overlay_gallery_max) settings.overlay_gallery = false; - - set_position = jQuery.inArray($(this).attr('href'), pp_images); // Define where in the array the clicked item is positionned - rel_index = (isSet) ? set_position : $("a["+settings.hook+"^='"+theRel+"']").index($(this)); - - _build_overlay(this); // Build the overlay {this} being the caller - - if(settings.allow_resize) - $(window).bind('scroll.prettyphoto',function(){ _center_overlay(); }); - - - $.prettyPhoto.open(); - - return false; - } - - - /** - * Opens the prettyPhoto modal box. - * @param image {String,Array} Full path to the image to be open, can also be an array containing full images paths. - * @param title {String,Array} The title to be displayed with the picture, can also be an array containing all the titles. - * @param description {String,Array} The description to be displayed with the picture, can also be an array containing all the descriptions. - */ - $.prettyPhoto.open = function(event) { - if(typeof settings == "undefined"){ // Means it's an API call, need to manually get the settings and set the variables - settings = pp_settings; - pp_images = $.makeArray(arguments[0]); - pp_titles = (arguments[1]) ? $.makeArray(arguments[1]) : $.makeArray(""); - pp_descriptions = (arguments[2]) ? $.makeArray(arguments[2]) : $.makeArray(""); - isSet = (pp_images.length > 1) ? true : false; - set_position = (arguments[3])? arguments[3]: 0; - _build_overlay(event.target); // Build the overlay {this} being the caller - } - - if(settings.hideflash) $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css('visibility','hidden'); // Hide the flash - - _checkPosition($(pp_images).size()); // Hide the next/previous links if on first or last images. - - $('.pp_loaderIcon').show(); - - if(settings.deeplinking) - setHashtag(); - - // Rebuild Facebook Like Button with updated href - if(settings.social_tools){ - facebook_like_link = settings.social_tools.replace('{location_href}', encodeURIComponent(location.href)); - $pp_pic_holder.find('.pp_social').html(facebook_like_link); - } - - // Fade the content in - if($ppt.is(':hidden')) $ppt.css('opacity',0).show(); - $pp_overlay.show().fadeTo(settings.animation_speed,settings.opacity); - - // Display the current position - $pp_pic_holder.find('.currentTextHolder').text((set_position+1) + settings.counter_separator_label + $(pp_images).size()); - - // Set the description - if(typeof pp_descriptions[set_position] != 'undefined' && pp_descriptions[set_position] != ""){ - $pp_pic_holder.find('.pp_description').show().html(unescape(pp_descriptions[set_position])); - }else{ - $pp_pic_holder.find('.pp_description').hide(); - } - - // Get the dimensions - movie_width = ( parseFloat(getParam('width',pp_images[set_position])) ) ? getParam('width',pp_images[set_position]) : settings.default_width.toString(); - movie_height = ( parseFloat(getParam('height',pp_images[set_position])) ) ? getParam('height',pp_images[set_position]) : settings.default_height.toString(); - - // If the size is % based, calculate according to window dimensions - percentBased=false; - if(movie_height.indexOf('%') != -1) { movie_height = parseFloat(($(window).height() * parseFloat(movie_height) / 100) - 150); percentBased = true; } - if(movie_width.indexOf('%') != -1) { movie_width = parseFloat(($(window).width() * parseFloat(movie_width) / 100) - 150); percentBased = true; } - - // Fade the holder - $pp_pic_holder.fadeIn(function(){ - // Set the title - (settings.show_title && pp_titles[set_position] != "" && typeof pp_titles[set_position] != "undefined") ? $ppt.html(unescape(pp_titles[set_position])) : $ppt.html(' '); - - imgPreloader = ""; - skipInjection = false; - - // Inject the proper content - switch(_getFileType(pp_images[set_position])){ - case 'image': - imgPreloader = new Image(); - - // Preload the neighbour images - nextImage = new Image(); - if(isSet && set_position < $(pp_images).size() -1) nextImage.src = pp_images[set_position + 1]; - prevImage = new Image(); - if(isSet && pp_images[set_position - 1]) prevImage.src = pp_images[set_position - 1]; - - $pp_pic_holder.find('#pp_full_res')[0].innerHTML = settings.image_markup.replace(/{path}/g,pp_images[set_position]); - - imgPreloader.onload = function(){ - // Fit item to viewport - pp_dimensions = _fitToViewport(imgPreloader.width,imgPreloader.height); - - _showContent(); - }; - - imgPreloader.onerror = function(){ - alert('Image cannot be loaded. Make sure the path is correct and image exist.'); - $.prettyPhoto.close(); - }; - - imgPreloader.src = pp_images[set_position]; - break; - - case 'youtube': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - - // Regular youtube link - movie_id = getParam('v',pp_images[set_position]); - - // youtu.be link - if(movie_id == ""){ - movie_id = pp_images[set_position].split('youtu.be/'); - movie_id = movie_id[1]; - if(movie_id.indexOf('?') > 0) - movie_id = movie_id.substr(0,movie_id.indexOf('?')); // Strip anything after the ? - - if(movie_id.indexOf('&') > 0) - movie_id = movie_id.substr(0,movie_id.indexOf('&')); // Strip anything after the & - } - - movie = 'http://www.youtube.com/embed/'+movie_id; - (getParam('rel',pp_images[set_position])) ? movie+="?rel="+getParam('rel',pp_images[set_position]) : movie+="?rel=1"; - - if(settings.autoplay) movie += "&autoplay=1"; - - toInject = settings.iframe_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,movie); - break; - - case 'vimeo': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - - movie_id = pp_images[set_position]; - var regExp = /http(s?):\/\/(www\.)?vimeo.com\/(\d+)/; - var match = movie_id.match(regExp); - - movie = 'http://player.vimeo.com/video/'+ match[3] +'?title=0&byline=0&portrait=0'; - if(settings.autoplay) movie += "&autoplay=1;"; - - vimeo_width = pp_dimensions['width'] + '/embed/?moog_width='+ pp_dimensions['width']; - - toInject = settings.iframe_markup.replace(/{width}/g,vimeo_width).replace(/{height}/g,pp_dimensions['height']).replace(/{path}/g,movie); - break; - - case 'quicktime': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - pp_dimensions['height']+=15; pp_dimensions['contentHeight']+=15; pp_dimensions['containerHeight']+=15; // Add space for the control bar - - toInject = settings.quicktime_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,pp_images[set_position]).replace(/{autoplay}/g,settings.autoplay); - break; - - case 'flash': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - - flash_vars = pp_images[set_position]; - flash_vars = flash_vars.substring(pp_images[set_position].indexOf('flashvars') + 10,pp_images[set_position].length); - - filename = pp_images[set_position]; - filename = filename.substring(0,filename.indexOf('?')); - - toInject = settings.flash_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,filename+'?'+flash_vars); - break; - - case 'iframe': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - - frame_url = pp_images[set_position]; - frame_url = frame_url.substr(0,frame_url.indexOf('iframe')-1); - - toInject = settings.iframe_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{path}/g,frame_url); - break; - - case 'ajax': - doresize = false; // Make sure the dimensions are not resized. - pp_dimensions = _fitToViewport(movie_width,movie_height); - doresize = true; // Reset the dimensions - - skipInjection = true; - $.get(pp_images[set_position],function(responseHTML){ - toInject = settings.inline_markup.replace(/{content}/g,responseHTML); - $pp_pic_holder.find('#pp_full_res')[0].innerHTML = toInject; - _showContent(); - }); - - break; - - case 'custom': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - - toInject = settings.custom_markup; - break; - - case 'inline': - // to get the item height clone it, apply default width, wrap it in the prettyPhoto containers , then delete - myClone = $(pp_images[set_position]).clone().append('
').css({'width':settings.default_width}).wrapInner('
').appendTo($('body')).show(); - doresize = false; // Make sure the dimensions are not resized. - pp_dimensions = _fitToViewport($(myClone).width(),$(myClone).height()); - doresize = true; // Reset the dimensions - $(myClone).remove(); - toInject = settings.inline_markup.replace(/{content}/g,$(pp_images[set_position]).html()); - break; - }; - - if(!imgPreloader && !skipInjection){ - $pp_pic_holder.find('#pp_full_res')[0].innerHTML = toInject; - - // Show content - _showContent(); - }; - }); - - return false; - }; - - - /** - * Change page in the prettyPhoto modal box - * @param direction {String} Direction of the paging, previous or next. - */ - $.prettyPhoto.changePage = function(direction){ - currentGalleryPage = 0; - - if(direction == 'previous') { - set_position--; - if (set_position < 0) set_position = $(pp_images).size()-1; - }else if(direction == 'next'){ - set_position++; - if(set_position > $(pp_images).size()-1) set_position = 0; - }else{ - set_position=direction; - }; - - rel_index = set_position; - - if(!doresize) doresize = true; // Allow the resizing of the images - if(settings.allow_expand) { - $('.pp_contract').removeClass('pp_contract').addClass('pp_expand'); - } - - _hideContent(function(){ $.prettyPhoto.open(); }); - }; - - - /** - * Change gallery page in the prettyPhoto modal box - * @param direction {String} Direction of the paging, previous or next. - */ - $.prettyPhoto.changeGalleryPage = function(direction){ - if(direction=='next'){ - currentGalleryPage ++; - - if(currentGalleryPage > totalPage) currentGalleryPage = 0; - }else if(direction=='previous'){ - currentGalleryPage --; - - if(currentGalleryPage < 0) currentGalleryPage = totalPage; - }else{ - currentGalleryPage = direction; - }; - - slide_speed = (direction == 'next' || direction == 'previous') ? settings.animation_speed : 0; - - slide_to = currentGalleryPage * (itemsPerPage * itemWidth); - - $pp_gallery.find('ul').animate({left:-slide_to},slide_speed); - }; - - - /** - * Start the slideshow... - */ - $.prettyPhoto.startSlideshow = function(){ - if(typeof pp_slideshow == 'undefined'){ - $pp_pic_holder.find('.pp_play').unbind('click').removeClass('pp_play').addClass('pp_pause').click(function(){ - $.prettyPhoto.stopSlideshow(); - return false; - }); - pp_slideshow = setInterval($.prettyPhoto.startSlideshow,settings.slideshow); - }else{ - $.prettyPhoto.changePage('next'); - }; - } - - - /** - * Stop the slideshow... - */ - $.prettyPhoto.stopSlideshow = function(){ - $pp_pic_holder.find('.pp_pause').unbind('click').removeClass('pp_pause').addClass('pp_play').click(function(){ - $.prettyPhoto.startSlideshow(); - return false; - }); - clearInterval(pp_slideshow); - pp_slideshow=undefined; - } - - - /** - * Closes prettyPhoto. - */ - $.prettyPhoto.close = function(){ - if($pp_overlay.is(":animated")) return; - - $.prettyPhoto.stopSlideshow(); - - $pp_pic_holder.stop().find('object,embed').css('visibility','hidden'); - - $('div.pp_pic_holder,div.ppt,.pp_fade').fadeOut(settings.animation_speed,function(){ $(this).remove(); }); - - $pp_overlay.fadeOut(settings.animation_speed, function(){ - - if(settings.hideflash) $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css('visibility','visible'); // Show the flash - - $(this).remove(); // No more need for the prettyPhoto markup - - $(window).unbind('scroll.prettyphoto'); - - clearHashtag(); - - settings.callback(); - - doresize = true; - - pp_open = false; - - delete settings; - }); - }; - - /** - * Set the proper sizes on the containers and animate the content in. - */ - function _showContent(){ - $('.pp_loaderIcon').hide(); - - // Calculate the opened top position of the pic holder - projectedTop = scroll_pos['scrollTop'] + ((windowHeight/2) - (pp_dimensions['containerHeight']/2)); - if(projectedTop < 0) projectedTop = 0; - - $ppt.fadeTo(settings.animation_speed,1); - - // Resize the content holder - $pp_pic_holder.find('.pp_content') - .animate({ - height:pp_dimensions['contentHeight'], - width:pp_dimensions['contentWidth'] - },settings.animation_speed); - - // Resize picture the holder - $pp_pic_holder.animate({ - 'top': projectedTop, - 'left': ((windowWidth/2) - (pp_dimensions['containerWidth']/2) < 0) ? 0 : (windowWidth/2) - (pp_dimensions['containerWidth']/2), - width:pp_dimensions['containerWidth'] - },settings.animation_speed,function(){ - $pp_pic_holder.find('.pp_hoverContainer,#fullResImage').height(pp_dimensions['height']).width(pp_dimensions['width']); - - $pp_pic_holder.find('.pp_fade').fadeIn(settings.animation_speed); // Fade the new content - - // Show the nav - if(isSet && _getFileType(pp_images[set_position])=="image") { $pp_pic_holder.find('.pp_hoverContainer').show(); }else{ $pp_pic_holder.find('.pp_hoverContainer').hide(); } - - if(settings.allow_expand) { - if(pp_dimensions['resized']){ // Fade the resizing link if the image is resized - $('a.pp_expand,a.pp_contract').show(); - }else{ - $('a.pp_expand').hide(); - } - } - - if(settings.autoplay_slideshow && !pp_slideshow && !pp_open) $.prettyPhoto.startSlideshow(); - - settings.changepicturecallback(); // Callback! - - pp_open = true; - }); - - _insert_gallery(); - pp_settings.ajaxcallback(); - }; - - /** - * Hide the content...DUH! - */ - function _hideContent(callback){ - // Fade out the current picture - $pp_pic_holder.find('#pp_full_res object,#pp_full_res embed').css('visibility','hidden'); - $pp_pic_holder.find('.pp_fade').fadeOut(settings.animation_speed,function(){ - $('.pp_loaderIcon').show(); - - callback(); - }); - }; - - /** - * Check the item position in the gallery array, hide or show the navigation links - * @param setCount {integer} The total number of items in the set - */ - function _checkPosition(setCount){ - (setCount > 1) ? $('.pp_nav').show() : $('.pp_nav').hide(); // Hide the bottom nav if it's not a set. - }; - - /** - * Resize the item dimensions if it's bigger than the viewport - * @param width {integer} Width of the item to be opened - * @param height {integer} Height of the item to be opened - * @return An array containin the "fitted" dimensions - */ - function _fitToViewport(width,height){ - resized = false; - - _getDimensions(width,height); - - // Define them in case there's no resize needed - imageWidth = width, imageHeight = height; - - if( ((pp_containerWidth > windowWidth) || (pp_containerHeight > windowHeight)) && doresize && settings.allow_resize && !percentBased) { - resized = true, fitting = false; - - while (!fitting){ - if((pp_containerWidth > windowWidth)){ - imageWidth = (windowWidth - 200); - imageHeight = (height/width) * imageWidth; - }else if((pp_containerHeight > windowHeight)){ - imageHeight = (windowHeight - 200); - imageWidth = (width/height) * imageHeight; - }else{ - fitting = true; - }; - - pp_containerHeight = imageHeight, pp_containerWidth = imageWidth; - }; - - - - if((pp_containerWidth > windowWidth) || (pp_containerHeight > windowHeight)){ - _fitToViewport(pp_containerWidth,pp_containerHeight) - }; - - _getDimensions(imageWidth,imageHeight); - }; - - return { - width:Math.floor(imageWidth), - height:Math.floor(imageHeight), - containerHeight:Math.floor(pp_containerHeight), - containerWidth:Math.floor(pp_containerWidth) + (settings.horizontal_padding * 2), - contentHeight:Math.floor(pp_contentHeight), - contentWidth:Math.floor(pp_contentWidth), - resized:resized - }; - }; - - /** - * Get the containers dimensions according to the item size - * @param width {integer} Width of the item to be opened - * @param height {integer} Height of the item to be opened - */ - function _getDimensions(width,height){ - width = parseFloat(width); - height = parseFloat(height); - - // Get the details height, to do so, I need to clone it since it's invisible - $pp_details = $pp_pic_holder.find('.pp_details'); - $pp_details.width(width); - detailsHeight = parseFloat($pp_details.css('marginTop')) + parseFloat($pp_details.css('marginBottom')); - - $pp_details = $pp_details.clone().addClass(settings.theme).width(width).appendTo($('body')).css({ - 'position':'absolute', - 'top':-10000 - }); - detailsHeight += $pp_details.height(); - detailsHeight = (detailsHeight <= 34) ? 36 : detailsHeight; // Min-height for the details - $pp_details.remove(); - - // Get the titles height, to do so, I need to clone it since it's invisible - $pp_title = $pp_pic_holder.find('.ppt'); - $pp_title.width(width); - titleHeight = parseFloat($pp_title.css('marginTop')) + parseFloat($pp_title.css('marginBottom')); - $pp_title = $pp_title.clone().appendTo($('body')).css({ - 'position':'absolute', - 'top':-10000 - }); - titleHeight += $pp_title.height(); - $pp_title.remove(); - - // Get the container size, to resize the holder to the right dimensions - pp_contentHeight = height + detailsHeight; - pp_contentWidth = width; - pp_containerHeight = pp_contentHeight + titleHeight + $pp_pic_holder.find('.pp_top').height() + $pp_pic_holder.find('.pp_bottom').height(); - pp_containerWidth = width; - } - - function _getFileType(itemSrc){ - if (itemSrc.match(/youtube\.com\/watch/i) || itemSrc.match(/youtu\.be/i)) { - return 'youtube'; - }else if (itemSrc.match(/vimeo\.com/i)) { - return 'vimeo'; - }else if(itemSrc.match(/\b.mov\b/i)){ - return 'quicktime'; - }else if(itemSrc.match(/\b.swf\b/i)){ - return 'flash'; - }else if(itemSrc.match(/\biframe=true\b/i)){ - return 'iframe'; - }else if(itemSrc.match(/\bajax=true\b/i)){ - return 'ajax'; - }else if(itemSrc.match(/\bcustom=true\b/i)){ - return 'custom'; - }else if(itemSrc.substr(0,1) == '#'){ - return 'inline'; - }else{ - return 'image'; - }; - }; - - function _center_overlay(){ - if(doresize && typeof $pp_pic_holder != 'undefined') { - scroll_pos = _get_scroll(); - contentHeight = $pp_pic_holder.height(), contentwidth = $pp_pic_holder.width(); - - projectedTop = (windowHeight/2) + scroll_pos['scrollTop'] - (contentHeight/2); - if(projectedTop < 0) projectedTop = 0; - - if(contentHeight > windowHeight) - return; - - $pp_pic_holder.css({ - 'top': projectedTop, - 'left': (windowWidth/2) + scroll_pos['scrollLeft'] - (contentwidth/2) - }); - }; - }; - - function _get_scroll(){ - if (self.pageYOffset) { - return {scrollTop:self.pageYOffset,scrollLeft:self.pageXOffset}; - } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict - return {scrollTop:document.documentElement.scrollTop,scrollLeft:document.documentElement.scrollLeft}; - } else if (document.body) {// all other Explorers - return {scrollTop:document.body.scrollTop,scrollLeft:document.body.scrollLeft}; - }; - }; - - function _resize_overlay() { - windowHeight = $(window).height(), windowWidth = $(window).width(); - - if(typeof $pp_overlay != "undefined") $pp_overlay.height($(document).height()).width(windowWidth); - }; - - function _insert_gallery(){ - if(isSet && settings.overlay_gallery && _getFileType(pp_images[set_position])=="image") { - itemWidth = 52+5; // 52 beign the thumb width, 5 being the right margin. - navWidth = (settings.theme == "facebook" || settings.theme == "pp_default") ? 50 : 30; // Define the arrow width depending on the theme - - itemsPerPage = Math.floor((pp_dimensions['containerWidth'] - 100 - navWidth) / itemWidth); - itemsPerPage = (itemsPerPage < pp_images.length) ? itemsPerPage : pp_images.length; - totalPage = Math.ceil(pp_images.length / itemsPerPage) - 1; - - // Hide the nav in the case there's no need for links - if(totalPage == 0){ - navWidth = 0; // No nav means no width! - $pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').hide(); - }else{ - $pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').show(); - }; - - galleryWidth = itemsPerPage * itemWidth; - fullGalleryWidth = pp_images.length * itemWidth; - - // Set the proper width to the gallery items - $pp_gallery - .css('margin-left',-((galleryWidth/2) + (navWidth/2))) - .find('div:first').width(galleryWidth+5) - .find('ul').width(fullGalleryWidth) - .find('li.selected').removeClass('selected'); - - goToPage = (Math.floor(set_position/itemsPerPage) < totalPage) ? Math.floor(set_position/itemsPerPage) : totalPage; - - $.prettyPhoto.changeGalleryPage(goToPage); - - $pp_gallery_li.filter(':eq('+set_position+')').addClass('selected'); - }else{ - $pp_pic_holder.find('.pp_content').unbind('mouseenter mouseleave'); - // $pp_gallery.hide(); - } - } - - function _build_overlay(caller){ - // Inject Social Tool markup into General markup - if(settings.social_tools) - facebook_like_link = settings.social_tools.replace('{location_href}', encodeURIComponent(location.href)); - - settings.markup = settings.markup.replace('{pp_social}',''); - - $('body').append(settings.markup); // Inject the markup - - $pp_pic_holder = $('.pp_pic_holder') , $ppt = $('.ppt'), $pp_overlay = $('div.pp_overlay'); // Set my global selectors - - // Inject the inline gallery! - if(isSet && settings.overlay_gallery) { - currentGalleryPage = 0; - toInject = ""; - for (var i=0; i < pp_images.length; i++) { - if(!pp_images[i].match(/\b(jpg|jpeg|png|gif)\b/gi)){ - classname = 'default'; - img_src = ''; - }else{ - classname = ''; - img_src = pp_images[i]; - } - toInject += "
  • "; - }; - - toInject = settings.gallery_markup.replace(/{gallery}/g,toInject); - - $pp_pic_holder.find('#pp_full_res').after(toInject); - - $pp_gallery = $('.pp_pic_holder .pp_gallery'), $pp_gallery_li = $pp_gallery.find('li'); // Set the gallery selectors - - $pp_gallery.find('.pp_arrow_next').click(function(){ - $.prettyPhoto.changeGalleryPage('next'); - $.prettyPhoto.stopSlideshow(); - return false; - }); - - $pp_gallery.find('.pp_arrow_previous').click(function(){ - $.prettyPhoto.changeGalleryPage('previous'); - $.prettyPhoto.stopSlideshow(); - return false; - }); - - $pp_pic_holder.find('.pp_content').hover( - function(){ - $pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeIn(); - }, - function(){ - $pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeOut(); - }); - - itemWidth = 52+5; // 52 beign the thumb width, 5 being the right margin. - $pp_gallery_li.each(function(i){ - $(this) - .find('a') - .click(function(){ - $.prettyPhoto.changePage(i); - $.prettyPhoto.stopSlideshow(); - return false; - }); - }); - }; - - - // Inject the play/pause if it's a slideshow - if(settings.slideshow){ - $pp_pic_holder.find('.pp_nav').prepend('Play') - $pp_pic_holder.find('.pp_nav .pp_play').click(function(){ - $.prettyPhoto.startSlideshow(); - return false; - }); - } - - $pp_pic_holder.attr('class','pp_pic_holder ' + settings.theme); // Set the proper theme - - $pp_overlay - .css({ - 'opacity':0, - 'height':$(document).height(), - 'width':$(window).width() - }) - .bind('click',function(){ - if(!settings.modal) $.prettyPhoto.close(); - }); - - $('a.pp_close').bind('click',function(){ $.prettyPhoto.close(); return false; }); - - - if(settings.allow_expand) { - $('a.pp_expand').bind('click',function(e){ - // Expand the image - if($(this).hasClass('pp_expand')){ - $(this).removeClass('pp_expand').addClass('pp_contract'); - doresize = false; - }else{ - $(this).removeClass('pp_contract').addClass('pp_expand'); - doresize = true; - }; - - _hideContent(function(){ $.prettyPhoto.open(); }); - - return false; - }); - } - - $pp_pic_holder.find('.pp_previous, .pp_nav .pp_arrow_previous').bind('click',function(){ - $.prettyPhoto.changePage('previous'); - $.prettyPhoto.stopSlideshow(); - return false; - }); - - $pp_pic_holder.find('.pp_next, .pp_nav .pp_arrow_next').bind('click',function(){ - $.prettyPhoto.changePage('next'); - $.prettyPhoto.stopSlideshow(); - return false; - }); - - _center_overlay(); // Center it - }; - - if(!pp_alreadyInitialized && getHashtag()){ - pp_alreadyInitialized = true; - - // Grab the rel index to trigger the click on the correct element - hashIndex = getHashtag(); - hashRel = hashIndex; - hashIndex = hashIndex.substring(hashIndex.indexOf('/')+1,hashIndex.length-1); - hashRel = hashRel.substring(0,hashRel.indexOf('/')); - - // Little timeout to make sure all the prettyPhoto initialize scripts has been run. - // Useful in the event the page contain several init scripts. - setTimeout(function(){ $("a["+pp_settings.hook+"^='"+hashRel+"']:eq("+hashIndex+")").trigger('click'); },50); - } - - return this.unbind('click.prettyphoto').bind('click.prettyphoto',$.prettyPhoto.initialize); // Return the jQuery object for chaining. The unbind method is used to avoid click conflict when the plugin is called more than once - }; - - function getHashtag(){ - var url = location.href; - hashtag = (url.indexOf('#prettyPhoto') !== -1) ? decodeURI(url.substring(url.indexOf('#prettyPhoto')+1,url.length)) : false; - - return hashtag; - }; - - function setHashtag(){ - if(typeof theRel == 'undefined') return; // theRel is set on normal calls, it's impossible to deeplink using the API - location.hash = theRel + '/'+rel_index+'/'; - }; - - function clearHashtag(){ - if ( location.href.indexOf('#prettyPhoto') !== -1 ) location.hash = "prettyPhoto"; - } - - function getParam(name,url){ - name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]"); - var regexS = "[\\?&]"+name+"=([^&#]*)"; - var regex = new RegExp( regexS ); - var results = regex.exec( url ); - return ( results == null ) ? "" : results[1]; - } - -})(jQuery); - -var pp_alreadyInitialized = false; // Used for the deep linking to make sure not to call the same function several times. diff --git a/dependency-check-core/src/test/resources/jquery.prettyPhoto_.js b/dependency-check-core/src/test/resources/jquery.prettyPhoto_.js deleted file mode 100644 index 51e7caa4d..000000000 --- a/dependency-check-core/src/test/resources/jquery.prettyPhoto_.js +++ /dev/null @@ -1,905 +0,0 @@ -/* ------------------------------------------------------------------------ - Class: prettyPhoto - Use: Lightbox clone for jQuery - Author: Stephane Caron (http://www.no-margin-for-errors.com) - Version: 3.1.3 -------------------------------------------------------------------------- */ -(function($) { - $.prettyPhoto = {version: '3.1.3'}; - - $.fn.prettyPhoto = function(pp_settings) { - pp_settings = jQuery.extend({ - animation_speed: 'fast', /* fast/slow/normal */ - slideshow: 5000, /* false OR interval time in ms */ - autoplay_slideshow: false, /* true/false */ - opacity: 0.80, /* Value between 0 and 1 */ - show_title: true, /* true/false */ - allow_resize: true, /* Resize the photos bigger than viewport. true/false */ - default_width: 500, - default_height: 344, - counter_separator_label: '/', /* The separator for the gallery counter 1 "of" 2 */ - theme: 'pp_default', /* light_rounded / dark_rounded / light_square / dark_square / facebook */ - horizontal_padding: 20, /* The padding on each side of the picture */ - hideflash: false, /* Hides all the flash object on a page, set to TRUE if flash appears over prettyPhoto */ - wmode: 'opaque', /* Set the flash wmode attribute */ - autoplay: true, /* Automatically start videos: True/False */ - modal: false, /* If set to true, only the close button will close the window */ - deeplinking: true, /* Allow prettyPhoto to update the url to enable deeplinking. */ - overlay_gallery: true, /* If set to true, a gallery will overlay the fullscreen image on mouse over */ - keyboard_shortcuts: true, /* Set to false if you open forms inside prettyPhoto */ - changepicturecallback: function(){}, /* Called everytime an item is shown/changed */ - callback: function(){}, /* Called when prettyPhoto is closed */ - ie6_fallback: true, - markup: '
    \ -
     
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ - Expand \ -
    \ - next \ - previous \ -
    \ -
    \ -
    \ -
    \ - Previous \ -

    0/0

    \ - Next \ -
    \ -

    \ -
    {pp_social}
    \ - Close \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    ', - gallery_markup: '', - image_markup: '', - flash_markup: '', - quicktime_markup: '', - iframe_markup: '', - inline_markup: '
    {content}
    ', - custom_markup: '', - social_tools: '' /* html or false to disable */ - }, pp_settings); - - // Global variables accessible only by prettyPhoto - var matchedObjects = this, percentBased = false, pp_dimensions, pp_open, - - // prettyPhoto container specific - pp_contentHeight, pp_contentWidth, pp_containerHeight, pp_containerWidth, - - // Window size - windowHeight = $(window).height(), windowWidth = $(window).width(), - - // Global elements - pp_slideshow; - - doresize = true, scroll_pos = _get_scroll(); - - // Window/Keyboard events - $(window).unbind('resize.prettyphoto').bind('resize.prettyphoto',function(){ _center_overlay(); _resize_overlay(); }); - - if(pp_settings.keyboard_shortcuts) { - $(document).unbind('keydown.prettyphoto').bind('keydown.prettyphoto',function(e){ - if(typeof $pp_pic_holder != 'undefined'){ - if($pp_pic_holder.is(':visible')){ - switch(e.keyCode){ - case 37: - $.prettyPhoto.changePage('previous'); - e.preventDefault(); - break; - case 39: - $.prettyPhoto.changePage('next'); - e.preventDefault(); - break; - case 27: - if(!settings.modal) - $.prettyPhoto.close(); - e.preventDefault(); - break; - }; - // return false; - }; - }; - }); - }; - - /** - * Initialize prettyPhoto. - */ - $.prettyPhoto.initialize = function() { - - settings = pp_settings; - - if(settings.theme == 'pp_default') settings.horizontal_padding = 16; - if(settings.ie6_fallback && $.browser.msie && parseInt($.browser.version) == 6) settings.theme = "light_square"; // Fallback to a supported theme for IE6 - - // Find out if the picture is part of a set - theRel = $(this).attr('rel'); - galleryRegExp = /\[(?:.*)\]/; - isSet = (galleryRegExp.exec(theRel)) ? true : false; - - // Put the SRCs, TITLEs, ALTs into an array. - pp_images = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr('rel').indexOf(theRel) != -1) return $(n).attr('href'); }) : $.makeArray($(this).attr('href')); - pp_titles = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr('rel').indexOf(theRel) != -1) return ($(n).find('img').attr('alt')) ? $(n).find('img').attr('alt') : ""; }) : $.makeArray($(this).find('img').attr('alt')); - pp_descriptions = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr('rel').indexOf(theRel) != -1) return ($(n).attr('title')) ? $(n).attr('title') : ""; }) : $.makeArray($(this).attr('title')); - - if(pp_images.length > 30) settings.overlay_gallery = false; - - set_position = jQuery.inArray($(this).attr('href'), pp_images); // Define where in the array the clicked item is positionned - rel_index = (isSet) ? set_position : $("a[rel^='"+theRel+"']").index($(this)); - - _build_overlay(this); // Build the overlay {this} being the caller - - if(settings.allow_resize) - $(window).bind('scroll.prettyphoto',function(){ _center_overlay(); }); - - - $.prettyPhoto.open(); - - return false; - } - - - /** - * Opens the prettyPhoto modal box. - * @param image {String,Array} Full path to the image to be open, can also be an array containing full images paths. - * @param title {String,Array} The title to be displayed with the picture, can also be an array containing all the titles. - * @param description {String,Array} The description to be displayed with the picture, can also be an array containing all the descriptions. - */ - $.prettyPhoto.open = function(event) { - if(typeof settings == "undefined"){ // Means it's an API call, need to manually get the settings and set the variables - settings = pp_settings; - if($.browser.msie && $.browser.version == 6) settings.theme = "light_square"; // Fallback to a supported theme for IE6 - pp_images = $.makeArray(arguments[0]); - pp_titles = (arguments[1]) ? $.makeArray(arguments[1]) : $.makeArray(""); - pp_descriptions = (arguments[2]) ? $.makeArray(arguments[2]) : $.makeArray(""); - isSet = (pp_images.length > 1) ? true : false; - set_position = 0; - _build_overlay(event.target); // Build the overlay {this} being the caller - } - - if($.browser.msie && $.browser.version == 6) $('select').css('visibility','hidden'); // To fix the bug with IE select boxes - - if(settings.hideflash) $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css('visibility','hidden'); // Hide the flash - - _checkPosition($(pp_images).size()); // Hide the next/previous links if on first or last images. - - $('.pp_loaderIcon').show(); - - if(settings.deeplinking) - setHashtag(); - - // Rebuild Facebook Like Button with updated href - if(settings.social_tools){ - facebook_like_link = settings.social_tools.replace('{location_href}', encodeURIComponent(location.href)); - $pp_pic_holder.find('.pp_social').html(facebook_like_link); - } - - // Fade the content in - if($ppt.is(':hidden')) $ppt.css('opacity',0).show(); - $pp_overlay.show().fadeTo(settings.animation_speed,settings.opacity); - - // Display the current position - $pp_pic_holder.find('.currentTextHolder').text((set_position+1) + settings.counter_separator_label + $(pp_images).size()); - - // Set the description - if(pp_descriptions[set_position] != ""){ - $pp_pic_holder.find('.pp_description').show().html(unescape(pp_descriptions[set_position])); - }else{ - $pp_pic_holder.find('.pp_description').hide(); - } - - // Get the dimensions - movie_width = ( parseFloat(getParam('width',pp_images[set_position])) ) ? getParam('width',pp_images[set_position]) : settings.default_width.toString(); - movie_height = ( parseFloat(getParam('height',pp_images[set_position])) ) ? getParam('height',pp_images[set_position]) : settings.default_height.toString(); - - // If the size is % based, calculate according to window dimensions - percentBased=false; - if(movie_height.indexOf('%') != -1) { movie_height = parseFloat(($(window).height() * parseFloat(movie_height) / 100) - 150); percentBased = true; } - if(movie_width.indexOf('%') != -1) { movie_width = parseFloat(($(window).width() * parseFloat(movie_width) / 100) - 150); percentBased = true; } - - // Fade the holder - $pp_pic_holder.fadeIn(function(){ - // Set the title - (settings.show_title && pp_titles[set_position] != "" && typeof pp_titles[set_position] != "undefined") ? $ppt.html(unescape(pp_titles[set_position])) : $ppt.html(' '); - - imgPreloader = ""; - skipInjection = false; - - // Inject the proper content - switch(_getFileType(pp_images[set_position])){ - case 'image': - imgPreloader = new Image(); - - // Preload the neighbour images - nextImage = new Image(); - if(isSet && set_position < $(pp_images).size() -1) nextImage.src = pp_images[set_position + 1]; - prevImage = new Image(); - if(isSet && pp_images[set_position - 1]) prevImage.src = pp_images[set_position - 1]; - - $pp_pic_holder.find('#pp_full_res')[0].innerHTML = settings.image_markup.replace(/{path}/g,pp_images[set_position]); - - imgPreloader.onload = function(){ - // Fit item to viewport - pp_dimensions = _fitToViewport(imgPreloader.width,imgPreloader.height); - - _showContent(); - }; - - imgPreloader.onerror = function(){ - alert('Image cannot be loaded. Make sure the path is correct and image exist.'); - $.prettyPhoto.close(); - }; - - imgPreloader.src = pp_images[set_position]; - break; - - case 'youtube': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - - // Regular youtube link - movie_id = getParam('v',pp_images[set_position]); - - // youtu.be link - if(movie_id == ""){ - movie_id = pp_images[set_position].split('youtu.be/'); - movie_id = movie_id[1]; - if(movie_id.indexOf('?') > 0) - movie_id = movie_id.substr(0,movie_id.indexOf('?')); // Strip anything after the ? - - if(movie_id.indexOf('&') > 0) - movie_id = movie_id.substr(0,movie_id.indexOf('&')); // Strip anything after the & - } - - movie = 'http://www.youtube.com/embed/'+movie_id; - (getParam('rel',pp_images[set_position])) ? movie+="?rel="+getParam('rel',pp_images[set_position]) : movie+="?rel=1"; - - if(settings.autoplay) movie += "&autoplay=1"; - - toInject = settings.iframe_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,movie); - break; - - case 'vimeo': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - - movie_id = pp_images[set_position]; - var regExp = /http:\/\/(www\.)?vimeo.com\/(\d+)/; - var match = movie_id.match(regExp); - - movie = 'http://player.vimeo.com/video/'+ match[2] +'?title=0&byline=0&portrait=0'; - if(settings.autoplay) movie += "&autoplay=1;"; - - vimeo_width = pp_dimensions['width'] + '/embed/?moog_width='+ pp_dimensions['width']; - - toInject = settings.iframe_markup.replace(/{width}/g,vimeo_width).replace(/{height}/g,pp_dimensions['height']).replace(/{path}/g,movie); - break; - - case 'quicktime': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - pp_dimensions['height']+=15; pp_dimensions['contentHeight']+=15; pp_dimensions['containerHeight']+=15; // Add space for the control bar - - toInject = settings.quicktime_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,pp_images[set_position]).replace(/{autoplay}/g,settings.autoplay); - break; - - case 'flash': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - - flash_vars = pp_images[set_position]; - flash_vars = flash_vars.substring(pp_images[set_position].indexOf('flashvars') + 10,pp_images[set_position].length); - - filename = pp_images[set_position]; - filename = filename.substring(0,filename.indexOf('?')); - - toInject = settings.flash_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,filename+'?'+flash_vars); - break; - - case 'iframe': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - - frame_url = pp_images[set_position]; - frame_url = frame_url.substr(0,frame_url.indexOf('iframe')-1); - - toInject = settings.iframe_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{path}/g,frame_url); - break; - - case 'ajax': - doresize = false; // Make sure the dimensions are not resized. - pp_dimensions = _fitToViewport(movie_width,movie_height); - doresize = true; // Reset the dimensions - - skipInjection = true; - $.get(pp_images[set_position],function(responseHTML){ - toInject = settings.inline_markup.replace(/{content}/g,responseHTML); - $pp_pic_holder.find('#pp_full_res')[0].innerHTML = toInject; - _showContent(); - }); - - break; - - case 'custom': - pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport - - toInject = settings.custom_markup; - break; - - case 'inline': - // to get the item height clone it, apply default width, wrap it in the prettyPhoto containers , then delete - myClone = $(pp_images[set_position]).clone().append('
    ').css({'width':settings.default_width}).wrapInner('
    ').appendTo($('body')).show(); - doresize = false; // Make sure the dimensions are not resized. - pp_dimensions = _fitToViewport($(myClone).width(),$(myClone).height()); - doresize = true; // Reset the dimensions - $(myClone).remove(); - toInject = settings.inline_markup.replace(/{content}/g,$(pp_images[set_position]).html()); - break; - }; - - if(!imgPreloader && !skipInjection){ - $pp_pic_holder.find('#pp_full_res')[0].innerHTML = toInject; - - // Show content - _showContent(); - }; - }); - - return false; - }; - - - /** - * Change page in the prettyPhoto modal box - * @param direction {String} Direction of the paging, previous or next. - */ - $.prettyPhoto.changePage = function(direction){ - currentGalleryPage = 0; - - if(direction == 'previous') { - set_position--; - if (set_position < 0) set_position = $(pp_images).size()-1; - }else if(direction == 'next'){ - set_position++; - if(set_position > $(pp_images).size()-1) set_position = 0; - }else{ - set_position=direction; - }; - - rel_index = set_position; - - if(!doresize) doresize = true; // Allow the resizing of the images - $('.pp_contract').removeClass('pp_contract').addClass('pp_expand'); - - _hideContent(function(){ $.prettyPhoto.open(); }); - }; - - - /** - * Change gallery page in the prettyPhoto modal box - * @param direction {String} Direction of the paging, previous or next. - */ - $.prettyPhoto.changeGalleryPage = function(direction){ - if(direction=='next'){ - currentGalleryPage ++; - - if(currentGalleryPage > totalPage) currentGalleryPage = 0; - }else if(direction=='previous'){ - currentGalleryPage --; - - if(currentGalleryPage < 0) currentGalleryPage = totalPage; - }else{ - currentGalleryPage = direction; - }; - - slide_speed = (direction == 'next' || direction == 'previous') ? settings.animation_speed : 0; - - slide_to = currentGalleryPage * (itemsPerPage * itemWidth); - - $pp_gallery.find('ul').animate({left:-slide_to},slide_speed); - }; - - - /** - * Start the slideshow... - */ - $.prettyPhoto.startSlideshow = function(){ - if(typeof pp_slideshow == 'undefined'){ - $pp_pic_holder.find('.pp_play').unbind('click').removeClass('pp_play').addClass('pp_pause').click(function(){ - $.prettyPhoto.stopSlideshow(); - return false; - }); - pp_slideshow = setInterval($.prettyPhoto.startSlideshow,settings.slideshow); - }else{ - $.prettyPhoto.changePage('next'); - }; - } - - - /** - * Stop the slideshow... - */ - $.prettyPhoto.stopSlideshow = function(){ - $pp_pic_holder.find('.pp_pause').unbind('click').removeClass('pp_pause').addClass('pp_play').click(function(){ - $.prettyPhoto.startSlideshow(); - return false; - }); - clearInterval(pp_slideshow); - pp_slideshow=undefined; - } - - - /** - * Closes prettyPhoto. - */ - $.prettyPhoto.close = function(){ - if($pp_overlay.is(":animated")) return; - - $.prettyPhoto.stopSlideshow(); - - $pp_pic_holder.stop().find('object,embed').css('visibility','hidden'); - - $('div.pp_pic_holder,div.ppt,.pp_fade').fadeOut(settings.animation_speed,function(){ $(this).remove(); }); - - $pp_overlay.fadeOut(settings.animation_speed, function(){ - if($.browser.msie && $.browser.version == 6) $('select').css('visibility','visible'); // To fix the bug with IE select boxes - - if(settings.hideflash) $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css('visibility','visible'); // Show the flash - - $(this).remove(); // No more need for the prettyPhoto markup - - $(window).unbind('scroll.prettyphoto'); - - clearHashtag(); - - settings.callback(); - - doresize = true; - - pp_open = false; - - delete settings; - }); - }; - - /** - * Set the proper sizes on the containers and animate the content in. - */ - function _showContent(){ - $('.pp_loaderIcon').hide(); - - // Calculate the opened top position of the pic holder - projectedTop = scroll_pos['scrollTop'] + ((windowHeight/2) - (pp_dimensions['containerHeight']/2)); - if(projectedTop < 0) projectedTop = 0; - - $ppt.fadeTo(settings.animation_speed,1); - - // Resize the content holder - $pp_pic_holder.find('.pp_content') - .animate({ - height:pp_dimensions['contentHeight'], - width:pp_dimensions['contentWidth'] - },settings.animation_speed); - - // Resize picture the holder - $pp_pic_holder.animate({ - 'top': projectedTop, - 'left': (windowWidth/2) - (pp_dimensions['containerWidth']/2), - width:pp_dimensions['containerWidth'] - },settings.animation_speed,function(){ - $pp_pic_holder.find('.pp_hoverContainer,#fullResImage').height(pp_dimensions['height']).width(pp_dimensions['width']); - - $pp_pic_holder.find('.pp_fade').fadeIn(settings.animation_speed); // Fade the new content - - // Show the nav - if(isSet && _getFileType(pp_images[set_position])=="image") { $pp_pic_holder.find('.pp_hoverContainer').show(); }else{ $pp_pic_holder.find('.pp_hoverContainer').hide(); } - - if(pp_dimensions['resized']){ // Fade the resizing link if the image is resized - $('a.pp_expand,a.pp_contract').show(); - }else{ - $('a.pp_expand').hide(); - } - - if(settings.autoplay_slideshow && !pp_slideshow && !pp_open) $.prettyPhoto.startSlideshow(); - - settings.changepicturecallback(); // Callback! - - pp_open = true; - }); - - _insert_gallery(); - }; - - /** - * Hide the content...DUH! - */ - function _hideContent(callback){ - // Fade out the current picture - $pp_pic_holder.find('#pp_full_res object,#pp_full_res embed').css('visibility','hidden'); - $pp_pic_holder.find('.pp_fade').fadeOut(settings.animation_speed,function(){ - $('.pp_loaderIcon').show(); - - callback(); - }); - }; - - /** - * Check the item position in the gallery array, hide or show the navigation links - * @param setCount {integer} The total number of items in the set - */ - function _checkPosition(setCount){ - (setCount > 1) ? $('.pp_nav').show() : $('.pp_nav').hide(); // Hide the bottom nav if it's not a set. - }; - - /** - * Resize the item dimensions if it's bigger than the viewport - * @param width {integer} Width of the item to be opened - * @param height {integer} Height of the item to be opened - * @return An array containin the "fitted" dimensions - */ - function _fitToViewport(width,height){ - resized = false; - - _getDimensions(width,height); - - // Define them in case there's no resize needed - imageWidth = width, imageHeight = height; - - if( ((pp_containerWidth > windowWidth) || (pp_containerHeight > windowHeight)) && doresize && settings.allow_resize && !percentBased) { - resized = true, fitting = false; - - while (!fitting){ - if((pp_containerWidth > windowWidth)){ - imageWidth = (windowWidth - 200); - imageHeight = (height/width) * imageWidth; - }else if((pp_containerHeight > windowHeight)){ - imageHeight = (windowHeight - 200); - imageWidth = (width/height) * imageHeight; - }else{ - fitting = true; - }; - - pp_containerHeight = imageHeight, pp_containerWidth = imageWidth; - }; - - _getDimensions(imageWidth,imageHeight); - - if((pp_containerWidth > windowWidth) || (pp_containerHeight > windowHeight)){ - _fitToViewport(pp_containerWidth,pp_containerHeight) - }; - }; - - return { - width:Math.floor(imageWidth), - height:Math.floor(imageHeight), - containerHeight:Math.floor(pp_containerHeight), - containerWidth:Math.floor(pp_containerWidth) + (settings.horizontal_padding * 2), - contentHeight:Math.floor(pp_contentHeight), - contentWidth:Math.floor(pp_contentWidth), - resized:resized - }; - }; - - /** - * Get the containers dimensions according to the item size - * @param width {integer} Width of the item to be opened - * @param height {integer} Height of the item to be opened - */ - function _getDimensions(width,height){ - width = parseFloat(width); - height = parseFloat(height); - - // Get the details height, to do so, I need to clone it since it's invisible - $pp_details = $pp_pic_holder.find('.pp_details'); - $pp_details.width(width); - detailsHeight = parseFloat($pp_details.css('marginTop')) + parseFloat($pp_details.css('marginBottom')); - - $pp_details = $pp_details.clone().addClass(settings.theme).width(width).appendTo($('body')).css({ - 'position':'absolute', - 'top':-10000 - }); - detailsHeight += $pp_details.height(); - detailsHeight = (detailsHeight <= 34) ? 36 : detailsHeight; // Min-height for the details - if($.browser.msie && $.browser.version==7) detailsHeight+=8; - $pp_details.remove(); - - // Get the titles height, to do so, I need to clone it since it's invisible - $pp_title = $pp_pic_holder.find('.ppt'); - $pp_title.width(width); - titleHeight = parseFloat($pp_title.css('marginTop')) + parseFloat($pp_title.css('marginBottom')); - $pp_title = $pp_title.clone().appendTo($('body')).css({ - 'position':'absolute', - 'top':-10000 - }); - titleHeight += $pp_title.height(); - $pp_title.remove(); - - // Get the container size, to resize the holder to the right dimensions - pp_contentHeight = height + detailsHeight; - pp_contentWidth = width; - pp_containerHeight = pp_contentHeight + titleHeight + $pp_pic_holder.find('.pp_top').height() + $pp_pic_holder.find('.pp_bottom').height(); - pp_containerWidth = width; - } - - function _getFileType(itemSrc){ - if (itemSrc.match(/youtube\.com\/watch/i) || itemSrc.match(/youtu\.be/i)) { - return 'youtube'; - }else if (itemSrc.match(/vimeo\.com/i)) { - return 'vimeo'; - }else if(itemSrc.match(/\b.mov\b/i)){ - return 'quicktime'; - }else if(itemSrc.match(/\b.swf\b/i)){ - return 'flash'; - }else if(itemSrc.match(/\biframe=true\b/i)){ - return 'iframe'; - }else if(itemSrc.match(/\bajax=true\b/i)){ - return 'ajax'; - }else if(itemSrc.match(/\bcustom=true\b/i)){ - return 'custom'; - }else if(itemSrc.substr(0,1) == '#'){ - return 'inline'; - }else{ - return 'image'; - }; - }; - - function _center_overlay(){ - if(doresize && typeof $pp_pic_holder != 'undefined') { - scroll_pos = _get_scroll(); - contentHeight = $pp_pic_holder.height(), contentwidth = $pp_pic_holder.width(); - - projectedTop = (windowHeight/2) + scroll_pos['scrollTop'] - (contentHeight/2); - if(projectedTop < 0) projectedTop = 0; - - if(contentHeight > windowHeight) - return; - - $pp_pic_holder.css({ - 'top': projectedTop, - 'left': (windowWidth/2) + scroll_pos['scrollLeft'] - (contentwidth/2) - }); - }; - }; - - function _get_scroll(){ - if (self.pageYOffset) { - return {scrollTop:self.pageYOffset,scrollLeft:self.pageXOffset}; - } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict - return {scrollTop:document.documentElement.scrollTop,scrollLeft:document.documentElement.scrollLeft}; - } else if (document.body) {// all other Explorers - return {scrollTop:document.body.scrollTop,scrollLeft:document.body.scrollLeft}; - }; - }; - - function _resize_overlay() { - windowHeight = $(window).height(), windowWidth = $(window).width(); - - if(typeof $pp_overlay != "undefined") $pp_overlay.height($(document).height()).width(windowWidth); - }; - - function _insert_gallery(){ - if(isSet && settings.overlay_gallery && _getFileType(pp_images[set_position])=="image" && (settings.ie6_fallback && !($.browser.msie && parseInt($.browser.version) == 6))) { - itemWidth = 52+5; // 52 beign the thumb width, 5 being the right margin. - navWidth = (settings.theme == "facebook" || settings.theme == "pp_default") ? 50 : 30; // Define the arrow width depending on the theme - - itemsPerPage = Math.floor((pp_dimensions['containerWidth'] - 100 - navWidth) / itemWidth); - itemsPerPage = (itemsPerPage < pp_images.length) ? itemsPerPage : pp_images.length; - totalPage = Math.ceil(pp_images.length / itemsPerPage) - 1; - - // Hide the nav in the case there's no need for links - if(totalPage == 0){ - navWidth = 0; // No nav means no width! - $pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').hide(); - }else{ - $pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').show(); - }; - - galleryWidth = itemsPerPage * itemWidth; - fullGalleryWidth = pp_images.length * itemWidth; - - // Set the proper width to the gallery items - $pp_gallery - .css('margin-left',-((galleryWidth/2) + (navWidth/2))) - .find('div:first').width(galleryWidth+5) - .find('ul').width(fullGalleryWidth) - .find('li.selected').removeClass('selected'); - - goToPage = (Math.floor(set_position/itemsPerPage) < totalPage) ? Math.floor(set_position/itemsPerPage) : totalPage; - - $.prettyPhoto.changeGalleryPage(goToPage); - - $pp_gallery_li.filter(':eq('+set_position+')').addClass('selected'); - }else{ - $pp_pic_holder.find('.pp_content').unbind('mouseenter mouseleave'); - // $pp_gallery.hide(); - } - } - - function _build_overlay(caller){ - // Inject Social Tool markup into General markup - if(settings.social_tools) - facebook_like_link = settings.social_tools.replace('{location_href}', encodeURIComponent(location.href)); - - settings.markup=settings.markup.replace('{pp_social}',(settings.social_tools)?facebook_like_link:''); - - $('body').append(settings.markup); // Inject the markup - - $pp_pic_holder = $('.pp_pic_holder') , $ppt = $('.ppt'), $pp_overlay = $('div.pp_overlay'); // Set my global selectors - - // Inject the inline gallery! - if(isSet && settings.overlay_gallery) { - currentGalleryPage = 0; - toInject = ""; - for (var i=0; i < pp_images.length; i++) { - if(!pp_images[i].match(/\b(jpg|jpeg|png|gif)\b/gi)){ - classname = 'default'; - img_src = ''; - }else{ - classname = ''; - img_src = pp_images[i]; - } - toInject += "
  • "; - }; - - toInject = settings.gallery_markup.replace(/{gallery}/g,toInject); - - $pp_pic_holder.find('#pp_full_res').after(toInject); - - $pp_gallery = $('.pp_pic_holder .pp_gallery'), $pp_gallery_li = $pp_gallery.find('li'); // Set the gallery selectors - - $pp_gallery.find('.pp_arrow_next').click(function(){ - $.prettyPhoto.changeGalleryPage('next'); - $.prettyPhoto.stopSlideshow(); - return false; - }); - - $pp_gallery.find('.pp_arrow_previous').click(function(){ - $.prettyPhoto.changeGalleryPage('previous'); - $.prettyPhoto.stopSlideshow(); - return false; - }); - - $pp_pic_holder.find('.pp_content').hover( - function(){ - $pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeIn(); - }, - function(){ - $pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeOut(); - }); - - itemWidth = 52+5; // 52 beign the thumb width, 5 being the right margin. - $pp_gallery_li.each(function(i){ - $(this) - .find('a') - .click(function(){ - $.prettyPhoto.changePage(i); - $.prettyPhoto.stopSlideshow(); - return false; - }); - }); - }; - - - // Inject the play/pause if it's a slideshow - if(settings.slideshow){ - $pp_pic_holder.find('.pp_nav').prepend('Play') - $pp_pic_holder.find('.pp_nav .pp_play').click(function(){ - $.prettyPhoto.startSlideshow(); - return false; - }); - } - - $pp_pic_holder.attr('class','pp_pic_holder ' + settings.theme); // Set the proper theme - - $pp_overlay - .css({ - 'opacity':0, - 'height':$(document).height(), - 'width':$(window).width() - }) - .bind('click',function(){ - if(!settings.modal) $.prettyPhoto.close(); - }); - - $('a.pp_close').bind('click',function(){ $.prettyPhoto.close(); return false; }); - - $('a.pp_expand').bind('click',function(e){ - // Expand the image - if($(this).hasClass('pp_expand')){ - $(this).removeClass('pp_expand').addClass('pp_contract'); - doresize = false; - }else{ - $(this).removeClass('pp_contract').addClass('pp_expand'); - doresize = true; - }; - - _hideContent(function(){ $.prettyPhoto.open(); }); - - return false; - }); - - $pp_pic_holder.find('.pp_previous, .pp_nav .pp_arrow_previous').bind('click',function(){ - $.prettyPhoto.changePage('previous'); - $.prettyPhoto.stopSlideshow(); - return false; - }); - - $pp_pic_holder.find('.pp_next, .pp_nav .pp_arrow_next').bind('click',function(){ - $.prettyPhoto.changePage('next'); - $.prettyPhoto.stopSlideshow(); - return false; - }); - - _center_overlay(); // Center it - }; - - if(!pp_alreadyInitialized && getHashtag()){ - pp_alreadyInitialized = true; - - // Grab the rel index to trigger the click on the correct element - hashIndex = getHashtag(); - hashRel = hashIndex; - hashIndex = hashIndex.substring(hashIndex.indexOf('/')+1,hashIndex.length-1); - hashRel = hashRel.substring(0,hashRel.indexOf('/')); - - // Little timeout to make sure all the prettyPhoto initialize scripts has been run. - // Useful in the event the page contain several init scripts. - setTimeout(function(){ $("a[rel^='"+hashRel+"']:eq("+hashIndex+")").trigger('click'); },50); - } - - return this.unbind('click.prettyphoto').bind('click.prettyphoto',$.prettyPhoto.initialize); // Return the jQuery object for chaining. The unbind method is used to avoid click conflict when the plugin is called more than once - }; - - function getHashtag(){ - url = location.href; - hashtag = (url.indexOf('#!') != -1) ? decodeURI(url.substring(url.indexOf('#!')+2,url.length)) : false; - return hashtag; - }; - - function setHashtag(){ - if(typeof theRel == 'undefined') return; // theRel is set on normal calls, it's impossible to deeplink using the API - location.hash = '!' + theRel + '/'+rel_index+'/'; - }; - - function clearHashtag(){ - // Clear the hashtag only if it was set by prettyPhoto - url = location.href; - hashtag = (url.indexOf('#!prettyPhoto')) ? true : false; - if(hashtag) location.hash = "!prettyPhoto"; - } - - function getParam(name,url){ - name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]"); - var regexS = "[\\?&]"+name+"=([^&#]*)"; - var regex = new RegExp( regexS ); - var results = regex.exec( url ); - return ( results == null ) ? "" : results[1]; - } - -})(jQuery); - -var pp_alreadyInitialized = false; // Used for the deep linking to make sure not to call the same function several times. \ No newline at end of file From 0a4c3102dde4096c44d4a980b1c73639562e0f59 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Thu, 9 Jul 2015 07:07:10 -0400 Subject: [PATCH 40/41] reverted changes as a schema upgrade is not needed at this time Former-commit-id: 6f97fef5748a3d630a73f790cca8baa4753e1d7a --- .../src/test/resources/dependencycheck.properties | 2 +- .../src/test/resources/dependencycheck.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dependency-check-core/src/test/resources/dependencycheck.properties b/dependency-check-core/src/test/resources/dependencycheck.properties index 541ce329d..84c3597be 100644 --- a/dependency-check-core/src/test/resources/dependencycheck.properties +++ b/dependency-check-core/src/test/resources/dependencycheck.properties @@ -20,7 +20,7 @@ data.directory=[JAR]/data # based databases the below filename will be added to the data directory above and then # if the connection string has a %s it will be replaced by the directory/filename path. data.file_name=dc.h2.db -data.version=3.0 +data.version=2.9 data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON; #data.connection_string=jdbc:mysql://localhost:3306/dependencycheck diff --git a/dependency-check-utils/src/test/resources/dependencycheck.properties b/dependency-check-utils/src/test/resources/dependencycheck.properties index 447247e30..3e8480667 100644 --- a/dependency-check-utils/src/test/resources/dependencycheck.properties +++ b/dependency-check-utils/src/test/resources/dependencycheck.properties @@ -17,7 +17,7 @@ engine.version.url=http://jeremylong.github.io/DependencyCheck/current.txt # below contains a %s then the data.directory will replace the %s. data.directory=[JAR]/data data.file_name=dc.h2.db -data.version=3.0 +data.version=2.9 data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON; #data.connection_string=jdbc:h2:file:%s;AUTO_SERVER=TRUE;AUTOCOMMIT=ON; #data.connection_string=jdbc:mysql://localhost:3306/dependencycheck From b227cf890b67c3c24f834736a4e142e0896ebe64 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Thu, 9 Jul 2015 07:07:36 -0400 Subject: [PATCH 41/41] checkstyle recommended updates Former-commit-id: 17e3e4580553c07b33533f1e9f6cb5f33177f78e --- .../org/owasp/dependencycheck/Engine.java | 8 ++--- .../agent/DependencyCheckScanAgent.java | 7 ++-- .../analyzer/AbstractFileTypeAnalyzer.java | 36 ++++++++----------- .../analyzer/ArchiveAnalyzer.java | 33 ++++++++++------- .../analyzer/AssemblyAnalyzer.java | 19 +++++++--- .../analyzer/AutoconfAnalyzer.java | 9 +++++ .../analyzer/CentralAnalyzer.java | 14 +++++--- .../dependencycheck/analyzer/JarAnalyzer.java | 8 +++++ .../analyzer/NexusAnalyzer.java | 18 ++++++++-- .../analyzer/NuspecAnalyzer.java | 8 +++++ .../analyzer/PythonDistributionAnalyzer.java | 31 +++++++++++----- .../analyzer/PythonPackageAnalyzer.java | 8 +++++ .../data/nvdcve/ConnectionFactory.java | 9 +++++ .../dependencycheck/data/nvdcve/CveDB.java | 1 - .../data/update/CpeUpdater.java | 6 ++-- .../data/update/NvdCveUpdater.java | 5 +-- .../data/update/UpdateService.java | 1 - .../data/update/cpe/CPEHandler.java | 20 ++++++----- .../dependencycheck/data/update/cpe/Cpe.java | 21 ++++++++--- .../data/update/nvd/ProcessTask.java | 10 +++--- .../dependencycheck/utils/DCResources.java | 2 +- .../dependencycheck/utils/ExtractionUtil.java | 5 +-- .../utils/FileFilterBuilder.java | 34 ++++++++++++------ 23 files changed, 208 insertions(+), 105 deletions(-) diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java index a5b232990..0b0c7e0a3 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/Engine.java @@ -51,7 +51,7 @@ import java.util.Set; * * @author Jeremy Long */ -public class Engine implements FileFilter{ +public class Engine implements FileFilter { /** * The list of dependencies. @@ -331,8 +331,8 @@ public class Engine implements FileFilter{ /** * Runs the analyzers against all of the dependencies. Since the mutable dependencies list is exposed via * {@link #getDependencies()}, this method iterates over a copy of the dependencies list. Thus, the potential for - * {@link java.util.ConcurrentModificationException}s is avoided, and analyzers may safely add or remove entries - * from the dependencies list. + * {@link java.util.ConcurrentModificationException}s is avoided, and analyzers may safely add or remove entries from the + * dependencies list. */ public void analyzeDependencies() { boolean autoUpdate = true; @@ -511,7 +511,7 @@ public class Engine implements FileFilter{ /** * Checks the CPE Index to ensure documents exists. If none exist a NoDataException is thrown. * - * @throws NoDataException thrown if no data exists in the CPE Index + * @throws NoDataException thrown if no data exists in the CPE Index * @throws DatabaseException thrown if there is an exception opening the database */ private void ensureDataExists() throws NoDataException, DatabaseException { diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java index 45fc8d050..7420e5302 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java @@ -872,7 +872,7 @@ public class DependencyCheckScanAgent { r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name()); } catch (IOException ex) { LOGGER.error( - "Unexpected exception occurred during analysis; please see the verbose error log for more details."); + "Unexpected exception occurred during analysis; please see the verbose error log for more details."); LOGGER.debug("", ex); } catch (Throwable ex) { LOGGER.error( @@ -1058,8 +1058,9 @@ public class DependencyCheckScanAgent { } } if (summary.length() > 0) { - LOGGER.warn("\n\nOne or more dependencies were identified with known vulnerabilities:\n\n{}\n\nSee the dependency-check report for more details.\n\n", - summary.toString()); + LOGGER.warn("\n\nOne or more dependencies were identified with known vulnerabilities:\n\n{}\n\n" + + "See the dependency-check report for more details.\n\n", + summary.toString()); } } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java index a59cea4ad..6f23a75b2 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractFileTypeAnalyzer.java @@ -39,10 +39,8 @@ import java.util.Set; public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer { // - /** - * Base constructor that all children must call. This checks the configuration to determine if the analyzer is - * enabled. + * Base constructor that all children must call. This checks the configuration to determine if the analyzer is enabled. */ public AbstractFileTypeAnalyzer() { reset(); @@ -102,18 +100,16 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen // // - /** *

    - * Returns the {@link java.io.FileFilter} used to determine which files are to be analyzed. - * An example would be an analyzer that inspected Java jar files. Implementors may use - * {@link org.owasp.dependencycheck.utils.FileFilterBuilder}.

    + * Returns the {@link java.io.FileFilter} used to determine which files are to be analyzed. An example would be an analyzer + * that inspected Java jar files. Implementors may use {@link org.owasp.dependencycheck.utils.FileFilterBuilder}.

    * * @return the file filter used to determine which files are to be analyzed *

    *

    - * If the analyzer returns null it will not cause additional files to be analyzed, but will be executed against - * every file loaded.

    + * If the analyzer returns null it will not cause additional files to be analyzed, but will be executed against every file + * loaded.

    */ protected abstract FileFilter getFileFilter(); @@ -125,11 +121,11 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen protected abstract void initializeFileTypeAnalyzer() throws Exception; /** - * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, - * scanned, and added to the list of dependencies within the engine. + * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned, + * and added to the list of dependencies within the engine. * * @param dependency the dependency to analyze - * @param engine the engine scanning + * @param engine the engine scanning * @throws AnalysisException thrown if there is an analysis exception */ protected abstract void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException; @@ -144,7 +140,6 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen //
    // - /** * Initializes the analyzer. * @@ -175,11 +170,11 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen } /** - * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, - * scanned, and added to the list of dependencies within the engine. + * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned, + * and added to the list of dependencies within the engine. * * @param dependency the dependency to analyze - * @param engine the engine scanning + * @param engine the engine scanning * @throws AnalysisException thrown if there is an analysis exception */ @Override @@ -191,7 +186,7 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen @Override public boolean accept(File pathname) { - FileFilter filter = getFileFilter(); + final FileFilter filter = getFileFilter(); boolean accepted = false; if (null == filter) { LOGGER.error("The '{}' analyzer is misconfigured and does not have a file filter; it will be disabled", getName()); @@ -205,13 +200,11 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen } // - // - /** *

    - * Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a - * final static declaration.

    + * Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a final static + * declaration.

    *

    *

    * This implementation was copied from @@ -226,6 +219,5 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen return set; } - // } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java index ebe2eb19e..1c65608e8 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java @@ -17,7 +17,14 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.*; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -47,8 +54,8 @@ import org.slf4j.LoggerFactory; /** *

    - * An analyzer that extracts files from archives and ensures any supported files contained within the archive are added - * to the dependency list.

    + * An analyzer that extracts files from archives and ensures any supported files contained within the archive are added to the + * dependency list.

    * * @author Jeremy Long */ @@ -93,8 +100,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { */ private static final Set ZIPPABLES = newHashSet("zip", "ear", "war", "jar", "sar", "apk", "nupkg"); /** - * The set of file extensions supported by this analyzer. Note for developers, any additions to this list will need - * to be explicitly handled in extractFiles(). + * The set of file extensions supported by this analyzer. Note for developers, any additions to this list will need to be + * explicitly handled in extractFiles(). */ private static final Set EXTENSIONS = newHashSet("tar", "gz", "tgz"); @@ -186,11 +193,11 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { } /** - * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, - * scanned, and added to the list of dependencies within the engine. + * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned, + * and added to the list of dependencies within the engine. * * @param dependency the dependency to analyze - * @param engine the engine scanning + * @param engine the engine scanning * @throws AnalysisException thrown if there is an analysis exception */ @Override @@ -288,9 +295,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { /** * Extracts the contents of an archive into the specified directory. * - * @param archive an archive file such as a WAR or EAR + * @param archive an archive file such as a WAR or EAR * @param destination a directory to extract the contents to - * @param engine the scanning engine + * @param engine the scanning engine * @throws AnalysisException thrown if the archive is not found */ private void extractFiles(File archive, File destination, Engine engine) throws AnalysisException { @@ -336,9 +343,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { /** * Extracts files from an archive. * - * @param input the archive to extract files from + * @param input the archive to extract files from * @param destination the location to write the files too - * @param engine the dependency-check engine + * @param engine the dependency-check engine * @throws ArchiveExtractionException thrown if there is an exception extracting files from the archive */ private void extractArchive(ArchiveInputStream input, File destination, Engine engine) throws ArchiveExtractionException { @@ -421,7 +428,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer { * Decompresses a file. * * @param inputStream the compressed file - * @param outputFile the location to write the decompressed file + * @param outputFile the location to write the decompressed file * @throws ArchiveExtractionException thrown if there is an exception decompressing the file */ private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException { diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java index 70701ced8..fff5e53ae 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java @@ -19,6 +19,13 @@ package org.owasp.dependencycheck.analyzer; import ch.qos.cal10n.IMessageConveyor; import ch.qos.cal10n.MessageConveyor; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Confidence; @@ -37,7 +44,6 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -73,15 +79,15 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer { /** * Message Conveyer */ - private final IMessageConveyor MESSAGE_CONVERYOR = new MessageConveyor(Locale.getDefault()); + private static final IMessageConveyor MESSAGE_CONVERYOR = new MessageConveyor(Locale.getDefault()); /** * LocLoggerFactory for localized logger */ - private final LocLoggerFactory LLFACTORY = new LocLoggerFactory(MESSAGE_CONVERYOR); + private static final LocLoggerFactory LLFACTORY = new LocLoggerFactory(MESSAGE_CONVERYOR); /** * Logger */ - private final LocLogger LOGGER = LLFACTORY.getLocLogger(AssemblyAnalyzer.class); + private static final LocLogger LOGGER = LLFACTORY.getLocLogger(AssemblyAnalyzer.class); /** * Builds the beginnings of a List for ProcessBuilder @@ -279,6 +285,11 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer { builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } + /** + * Removes resources used from the local file system. + * + * @throws Exception thrown if there is a problem closing the analyzer + */ @Override public void close() throws Exception { super.close(); diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java index f23e546a2..d25ad57de 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java @@ -103,9 +103,17 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer { | Pattern.CASE_INSENSITIVE); } + /** + * The file filter used to determine which files this analyzer supports. + */ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFilenames(CONFIGURE).addExtensions( EXTENSIONS).build(); + /** + * Returns the FileFilter + * + * @return the FileFilter + */ @Override protected FileFilter getFileFilter() { return FILTER; @@ -126,6 +134,7 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer { * * @return the phase that the analyzer is intended to run in. */ + @Override public AnalysisPhase getAnalysisPhase() { return ANALYSIS_PHASE; } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java index 029f25c45..70e8d3159 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java @@ -25,7 +25,6 @@ import org.owasp.dependencycheck.data.nexus.MavenArtifact; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Evidence; -import org.owasp.dependencycheck.utils.*; import org.owasp.dependencycheck.xml.pom.PomUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +35,11 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.util.List; +import org.owasp.dependencycheck.utils.DownloadFailedException; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.InvalidSettingException; +import org.owasp.dependencycheck.utils.Settings; /** * Analyzer which will attempt to locate a dependency, and the GAV information, by querying Central for the dependency's SHA-1 @@ -161,6 +165,9 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer { return ANALYSIS_PHASE; } + /** + * The file filter used to determine which files this analyzer supports. + */ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build(); @Override @@ -201,7 +208,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer { pomFile = File.createTempFile("pom", ".xml", baseDir); if (!pomFile.delete()) { LOGGER.warn("Unable to fetch pom.xml for {} from Central; " - + "this could result in undetected CPE/CVEs.", dependency.getFileName()); + + "this could result in undetected CPE/CVEs.", dependency.getFileName()); LOGGER.debug("Unable to delete temp file"); } LOGGER.debug("Downloading {}", ma.getPomUrl()); @@ -210,7 +217,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer { } catch (DownloadFailedException ex) { LOGGER.warn("Unable to download pom.xml for {} from Central; " - + "this could result in undetected CPE/CVEs.", dependency.getFileName()); + + "this could result in undetected CPE/CVEs.", dependency.getFileName()); } finally { if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) { pomFile.deleteOnExit(); @@ -228,5 +235,4 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer { errorFlag = true; } } - } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java index 94aaceb37..4c1c80145 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java @@ -164,8 +164,16 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer { */ private static final String[] EXTENSIONS = {"jar", "war"}; + /** + * The file filter used to determine which files this analyzer supports. + */ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build(); + /** + * Returns the FileFilter. + * + * @return the FileFilter + */ @Override protected FileFilter getFileFilter() { return FILTER; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java index 057a1e23a..226c0aff2 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java @@ -25,7 +25,6 @@ import org.owasp.dependencycheck.data.nexus.NexusSearch; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Evidence; -import org.owasp.dependencycheck.utils.*; import org.owasp.dependencycheck.xml.pom.PomUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +35,11 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import org.owasp.dependencycheck.utils.DownloadFailedException; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.InvalidSettingException; +import org.owasp.dependencycheck.utils.Settings; /** * Analyzer which will attempt to locate a dependency on a Nexus service by SHA-1 digest of the dependency. @@ -181,8 +185,16 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer { return ANALYSIS_PHASE; } + /** + * The file filter used to determine which files this analyzer supports. + */ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build(); + /** + * Returns the FileFilter + * + * @return the FileFilter + */ @Override protected FileFilter getFileFilter() { return FILTER; @@ -218,7 +230,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer { pomFile = File.createTempFile("pom", ".xml", baseDir); if (!pomFile.delete()) { LOGGER.warn("Unable to fetch pom.xml for {} from Nexus repository; " - + "this could result in undetected CPE/CVEs.", dependency.getFileName()); + + "this could result in undetected CPE/CVEs.", dependency.getFileName()); LOGGER.debug("Unable to delete temp file"); } LOGGER.debug("Downloading {}", ma.getPomUrl()); @@ -226,7 +238,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer { PomUtils.analyzePOM(dependency, pomFile); } catch (DownloadFailedException ex) { LOGGER.warn("Unable to download pom.xml for {} from Nexus repository; " - + "this could result in undetected CPE/CVEs.", dependency.getFileName()); + + "this could result in undetected CPE/CVEs.", dependency.getFileName()); } finally { if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) { pomFile.deleteOnExit(); diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java index 0082963b6..9e24f56f5 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java @@ -101,9 +101,17 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer { return ANALYSIS_PHASE; } + /** + * The file filter used to determine which files this analyzer supports. + */ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions( SUPPORTED_EXTENSIONS).build(); + /** + * Returns the FileFilter + * + * @return the FileFilter + */ @Override protected FileFilter getFileFilter() { return FILTER; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java index 530837945..87d21f168 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java @@ -26,7 +26,6 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.EvidenceCollection; -import org.owasp.dependencycheck.utils.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,6 +33,12 @@ import javax.mail.MessagingException; import javax.mail.internet.InternetHeaders; import java.io.*; import java.util.regex.Pattern; +import org.owasp.dependencycheck.utils.ExtractionException; +import org.owasp.dependencycheck.utils.ExtractionUtil; +import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.FileUtils; +import org.owasp.dependencycheck.utils.Settings; +import org.owasp.dependencycheck.utils.UrlStringUtils; /** * Used to analyze a Wheel or egg distribution files, or their contents in unzipped form, and collect information that can be used @@ -112,9 +117,17 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer { private static final NameFileFilter PKG_INFO_FILTER = new NameFileFilter( PKG_INFO); + /** + * The file filter used to determine which files this analyzer supports. + */ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFileFilters( METADATA_FILTER, PKG_INFO_FILTER).addExtensions(EXTENSIONS).build(); + /** + * Returns the FileFilter + * + * @return the FileFilter + */ @Override protected FileFilter getFileFilter() { return FILTER; @@ -181,13 +194,13 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer { /** * Collects the meta data from an archive. * - * @param dependency the archive being scanned - * @param folderFilter the filter to apply to the folder + * @param dependency the archive being scanned + * @param folderFilter the filter to apply to the folder * @param metadataFilter the filter to apply to the meta data * @throws AnalysisException thrown when there is a problem analyzing the dependency */ private void collectMetadataFromArchiveFormat(Dependency dependency, - FilenameFilter folderFilter, FilenameFilter metadataFilter) + FilenameFilter folderFilter, FilenameFilter metadataFilter) throws AnalysisException { final File temp = getNextTempDirectory(); LOGGER.debug("{} exists? {}", temp, temp.exists()); @@ -247,7 +260,7 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer { * Gathers evidence from the METADATA file. * * @param dependency the dependency being analyzed - * @param file a reference to the manifest/properties file + * @param file a reference to the manifest/properties file * @throws AnalysisException thrown when there is an error */ private static void collectWheelMetadata(Dependency dependency, File file) @@ -277,13 +290,13 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer { /** * Adds a value to the evidence collection. * - * @param headers the properties collection - * @param evidence the evidence collection to add the value - * @param property the property name + * @param headers the properties collection + * @param evidence the evidence collection to add the value + * @param property the property name * @param confidence the confidence of the evidence */ private static void addPropertyToEvidence(InternetHeaders headers, - EvidenceCollection evidence, String property, Confidence confidence) { + EvidenceCollection evidence, String property, Confidence confidence) { final String value = headers.getHeader(property, null); LOGGER.debug("Property: {}, Value: {}", property, value); if (StringUtils.isNotBlank(value)) { diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java index 6aba3e1f6..8f909614b 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java @@ -132,8 +132,16 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer { return AnalysisPhase.INFORMATION_COLLECTION; } + /** + * The file filter used to determine which files this analyzer supports. + */ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build(); + /** + * Returns the FileFilter + * + * @return the FileFilter + */ @Override protected FileFilter getFileFilter() { return FILTER; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java index 4855190a9..d787885f1 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java @@ -278,6 +278,15 @@ public final class ConnectionFactory { } } + /** + * Updates the database schema by loading the upgrade script for the version specified. The intended use is that if the + * current schema version is 2.9 then we would call updateSchema(conn, "2.9"). This would load the upgrade_2.9.sql file and + * execute it against the database. The upgrade script must update the 'version' in the properties table. + * + * @param conn the database connection object + * @param schema the current schema version that is being upgraded + * @throws DatabaseException thrown if there is an exception upgrading the database schema + */ private static void updateSchema(Connection conn, String schema) throws DatabaseException { LOGGER.debug("Updating database structure"); InputStream is; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java index c06050160..153c35cfd 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java @@ -34,7 +34,6 @@ import java.util.Map.Entry; import java.util.Properties; import java.util.ResourceBundle; import java.util.Set; -import java.util.logging.Level; import org.owasp.dependencycheck.data.cwe.CweDB; import org.owasp.dependencycheck.dependency.Reference; import org.owasp.dependencycheck.dependency.Vulnerability; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java index 637a4f2d9..0f6707488 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java @@ -64,7 +64,7 @@ public class CpeUpdater extends BaseUpdater implements CachedWebDataSource { if (updateNeeded()) { LOGGER.info("Updating the Common Platform Enumeration (CPE)"); final File xml = downloadCpe(); - List cpes = processXML(xml); + final List cpes = processXML(xml); getCveDB().deleteUnusedCpe(); for (Cpe cpe : cpes) { getCveDB().addCpe(cpe.getValue(), cpe.getVendor(), cpe.getProduct()); @@ -116,7 +116,7 @@ public class CpeUpdater extends BaseUpdater implements CachedWebDataSource { try { final SAXParserFactory factory = SAXParserFactory.newInstance(); final SAXParser saxParser = factory.newSAXParser(); - CPEHandler handler = new CPEHandler(); + final CPEHandler handler = new CPEHandler(); saxParser.parse(xml, handler); return handler.getData(); } catch (ParserConfigurationException ex) { @@ -137,7 +137,7 @@ public class CpeUpdater extends BaseUpdater implements CachedWebDataSource { final Date now = new Date(); final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 30); long timestamp = 0; - String ts = getProperties().getProperty(LAST_CPE_UPDATE); + final String ts = getProperties().getProperty(LAST_CPE_UPDATE); if (ts != null && ts.matches("^[0-9]+$")) { timestamp = Long.parseLong(ts); } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java index 94d03ca89..ef9aa2846 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java @@ -67,7 +67,7 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource { public void update() throws UpdateException { try { openDataStores(); - UpdateableNvdCve updateable = getUpdatesNeeded(); + final UpdateableNvdCve updateable = getUpdatesNeeded(); if (updateable.isUpdateNeeded()) { performUpdate(updateable); } @@ -233,7 +233,8 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource { } else { long currentTimestamp = 0; try { - currentTimestamp = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED_BASE + entry.getId(), "0")); + currentTimestamp = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED_BASE + + entry.getId(), "0")); } catch (NumberFormatException ex) { LOGGER.debug("Error parsing '{}' '{}' from nvdcve.lastupdated", DatabaseProperties.LAST_UPDATED_BASE, entry.getId(), ex); diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateService.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateService.java index 96fbda0d1..8720b3539 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateService.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateService.java @@ -19,7 +19,6 @@ package org.owasp.dependencycheck.data.update; import java.util.Iterator; import java.util.ServiceLoader; -import org.owasp.dependencycheck.data.update.CachedWebDataSource; /** * The CachedWebDataSource Service Loader. This class loads all services that implement diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java index 2f7461881..6a155c6ca 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java @@ -18,7 +18,6 @@ package org.owasp.dependencycheck.data.update.cpe; import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; import org.owasp.dependencycheck.data.update.NvdCveUpdater; @@ -43,11 +42,11 @@ public class CPEHandler extends DefaultHandler { /** * The text content of the node being processed. This can be used during the end element event. */ - StringBuilder nodeText = null; + private StringBuilder nodeText = null; /** * A reference to the current element. */ - Element current = new Element(); + private Element current = new Element(); /** * The logger. */ @@ -55,7 +54,7 @@ public class CPEHandler extends DefaultHandler { /** * The list of CPE values. */ - List data = new ArrayList(); + private List data = new ArrayList(); /** * Returns the list of CPE values. @@ -67,7 +66,7 @@ public class CPEHandler extends DefaultHandler { } /** - * Handles the start element event + * Handles the start element event. * * @param uri the elements uri * @param localName the local name @@ -80,12 +79,12 @@ public class CPEHandler extends DefaultHandler { nodeText = null; current.setNode(qName); if (current.isCpeItemNode()) { - String temp = attributes.getValue("deprecated"); - String value = attributes.getValue("name"); - boolean delete = (temp != null && temp.equalsIgnoreCase("true")); + final String temp = attributes.getValue("deprecated"); + final String value = attributes.getValue("name"); + final boolean delete = "true".equalsIgnoreCase(temp); if (!delete && value.startsWith("cpe:/a:") && value.length() > 7) { try { - Cpe cpe = new Cpe(value); + final Cpe cpe = new Cpe(value); data.add(cpe); } catch (UnsupportedEncodingException ex) { LOGGER.debug("Unable to parse the CPE", ex); @@ -230,6 +229,9 @@ public class CPEHandler extends DefaultHandler { * A node type in the CPE Schema 2.2 */ public static final String TIMESTAMP = "timestamp"; + /** + * A reference to the current node. + */ private String node = null; /** diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/Cpe.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/Cpe.java index 4309d2914..1d4c3cb33 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/Cpe.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/Cpe.java @@ -27,6 +27,13 @@ import org.owasp.dependencycheck.data.update.exception.InvalidDataException; */ public class Cpe { + /** + * Constructs a new Cpe Object by parsing the vendor and product from the CPE identifier value. + * + * @param value the cpe identifier (cpe:/a:vendor:product:version:....) + * @throws UnsupportedEncodingException thrown if UTF-8 is not supported + * @throws InvalidDataException thrown if the CPE provided is not the correct format + */ public Cpe(String value) throws UnsupportedEncodingException, InvalidDataException { this.value = value; final String[] data = value.substring(7).split(":"); @@ -66,7 +73,7 @@ public class Cpe { private String vendor; /** - * Get the value of vendor + * Get the value of vendor. * * @return the value of vendor */ @@ -75,7 +82,7 @@ public class Cpe { } /** - * Set the value of vendor + * Set the value of vendor. * * @param vendor new value of vendor */ @@ -89,7 +96,7 @@ public class Cpe { private String product; /** - * Get the value of product + * Get the value of product. * * @return the value of product */ @@ -98,7 +105,7 @@ public class Cpe { } /** - * Set the value of product + * Set the value of product. * * @param product new value of product */ @@ -106,9 +113,13 @@ public class Cpe { this.product = product; } + /** + * Returns the full CPE identifier. + * + * @return the full CPE identifier + */ @Override public String toString() { return value; } - } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java index df8c52819..8934337c9 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java @@ -31,8 +31,6 @@ import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; import org.owasp.dependencycheck.data.update.exception.UpdateException; -import org.owasp.dependencycheck.data.update.nvd.NvdCve12Handler; -import org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler; import org.owasp.dependencycheck.dependency.VulnerableSoftware; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; @@ -94,8 +92,8 @@ public class ProcessTask implements Callable { * * @param cveDB the data store object * @param filePair the download task that contains the URL references to download - * @param settings a reference to the global settings object; this is necessary so that when the thread is started - * the dependencies have a correct reference to the global settings. + * @param settings a reference to the global settings object; this is necessary so that when the thread is started the + * dependencies have a correct reference to the global settings. */ public ProcessTask(final CveDB cveDB, final DownloadTask filePair, Settings settings) { this.cveDB = cveDB; @@ -108,8 +106,8 @@ public class ProcessTask implements Callable { * Implements the callable interface. * * @return this object - * @throws Exception thrown if there is an exception; note that any UpdateExceptions are simply added to the tasks - * exception collection + * @throws Exception thrown if there is an exception; note that any UpdateExceptions are simply added to the tasks exception + * collection */ @Override public ProcessTask call() throws Exception { diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DCResources.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DCResources.java index 4eedc5f36..e0e8a0540 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DCResources.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DCResources.java @@ -22,7 +22,7 @@ import ch.qos.cal10n.Locale; import ch.qos.cal10n.LocaleData; /** - * Created by colezlaw on 6/13/15. + * @author colezlaw */ @BaseName("dependencycheck-resources") @LocaleData(defaultCharset = "UTF-8", diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java index c1caa5a05..6aed21164 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java @@ -17,8 +17,6 @@ */ package org.owasp.dependencycheck.utils; -import static org.owasp.dependencycheck.utils.FileUtils.getFileExtension; - import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable; @@ -226,7 +224,7 @@ public final class ExtractionUtil { final File file = new File(destination, entry.getName()); if (filter.accept(file.getParentFile(), file.getName())) { LOGGER.debug("Extracting '{}'", - file.getPath()); + file.getPath()); BufferedOutputStream bos = null; FileOutputStream fos = null; try { @@ -302,5 +300,4 @@ public final class ExtractionUtil { } } } - } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java index 25ee59726..0b9016adc 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java @@ -15,7 +15,6 @@ * * Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved. */ - package org.owasp.dependencycheck.utils; import org.apache.commons.io.IOCase; @@ -25,12 +24,17 @@ import org.apache.commons.io.filefilter.OrFileFilter; import org.apache.commons.io.filefilter.SuffixFileFilter; import java.io.FileFilter; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** - *

    Utility class for building useful {@link FileFilter} instances for - * {@link org.owasp.dependencycheck.analyzer.AbstractFileTypeAnalyzer} implementations. The built filter uses - * {@link OrFileFilter} to logically OR the given filter conditions. Example usage:

    + *

    + * Utility class for building useful {@link FileFilter} instances for + * {@link org.owasp.dependencycheck.analyzer.AbstractFileTypeAnalyzer} implementations. The built filter uses {@link OrFileFilter} + * to logically OR the given filter conditions. Example usage:

    * *
      *     FileFilter filter = FileFilterBuilder.newInstance().addExtensions("jar", "war").build();
    @@ -41,13 +45,21 @@ import java.util.*;
      */
     public class FileFilterBuilder {
     
    -    private Set filenames = new HashSet();
    -    private Set extensions = new HashSet();
    -    private List fileFilters = new ArrayList();
    +    /**
    +     * A set of filenames to filter.
    +     */
    +    private final Set filenames = new HashSet();
    +    /**
    +     * A set of extensions to filter.
    +     */
    +    private final Set extensions = new HashSet();
    +    /**
    +     * An array list of file filters.
    +     */
    +    private final List fileFilters = new ArrayList();
     
         /**
    -     * Create a new instance and return it. This method is for convenience in using the builder pattern within a single
    -     * statement.
    +     * Create a new instance and return it. This method is for convenience in using the builder pattern within a single statement.
          *
          * @return a new builder instance
          */
    @@ -111,7 +123,7 @@ public class FileFilterBuilder {
             if (filenames.isEmpty() && extensions.isEmpty() && fileFilters.isEmpty()) {
                 throw new IllegalStateException("May only be invoked after at least one add... method has been invoked.");
             }
    -        OrFileFilter filter = new OrFileFilter();
    +        final OrFileFilter filter = new OrFileFilter();
             if (!filenames.isEmpty()) {
                 filter.addFileFilter(new NameFileFilter(new ArrayList(filenames)));
             }