text:
fileFormatVersion: 2
guid: 0619a0da9a14dde40a4f3807859abde7
TextureImporter:
  internalIDToNameTable: []
  externalObjects: {}
  serializedVersion: 10
  mipmaps:
    mipMapMode: 0
    enableMipMap: 1
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    mipMapsPreserveCoverage: 0
    alphaTestReferenceValue: 0.5
    mipMapFadeDistanceStart: 1
    mipMapFadeDistanceEnd: 3
  bumpmap:
    convertToNormalMap: 0
    externalNormalMap: 0
    heightScale: 0.25
    normalMapFilter: 0
  isReadable: 0
  streamingMipmaps: 0
  streamingMipmapsPriority: 0
  grayScaleToAlpha: 0
  generateCubemap: 6
  cubemapConvolution: 0
  seamlessCubemap: 0
  textureFormat: 1
  maxTextureSize: 2048
  textureSettings:
    serializedVersion: 2
    filterMode: -1
    aniso: 2
    mipBias: -100
    wrapU: -1
    wrapV: -1
    wrapW: -1
  nPOTScale: 1
  lightmap: 0
  compressionQuality: 50
  spriteMode: 0
  spriteExtrude: 1
  spriteMeshType: 1
  alignment: 0
  spritePivot: {x: 0.5, y: 0.5}
  spritePixelsToUnits: 100
  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
  spriteGenerateFallbackPhysicsShape: 1
  alphaUsage: 1
  alphaIsTransparency: 0
  spriteTessellationDetail: -1
  textureType: 0
  textureShape: 1
  singleChannelComponent: 0
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  platformSettings:
  - serializedVersion: 3
    buildTarget: DefaultTexturePlatform
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Standalone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: iPhone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Android
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
    physicsShape: []
    bones: []
    spriteID:
    internalID: 0
    vertices: []
    indices:
    edges: []
    weights: []
    secondaryTextures: []
  spritePackingTag:
  pSDRemoveMatte: 0
  pSDShowRemoveMatteOption: 0
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: bbd4e694e6e502b48bf4d152471023ea
TextureImporter:
  internalIDToNameTable: []
  externalObjects: {}
  serializedVersion: 10
  mipmaps:
    mipMapMode: 0
    enableMipMap: 1
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    mipMapsPreserveCoverage: 0
    alphaTestReferenceValue: 0.5
    mipMapFadeDistanceStart: 1
    mipMapFadeDistanceEnd: 3
  bumpmap:
    convertToNormalMap: 0
    externalNormalMap: 0
    heightScale: 0.25
    normalMapFilter: 0
  isReadable: 0
  streamingMipmaps: 0
  streamingMipmapsPriority: 0
  grayScaleToAlpha: 0
  generateCubemap: 6
  cubemapConvolution: 0
  seamlessCubemap: 0
  textureFormat: 1
  maxTextureSize: 2048
  textureSettings:
    serializedVersion: 2
    filterMode: -1
    aniso: 2
    mipBias: -100
    wrapU: -1
    wrapV: -1
    wrapW: -1
  nPOTScale: 1
  lightmap: 0
  compressionQuality: 50
  spriteMode: 0
  spriteExtrude: 1
  spriteMeshType: 1
  alignment: 0
  spritePivot: {x: 0.5, y: 0.5}
  spritePixelsToUnits: 100
  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
  spriteGenerateFallbackPhysicsShape: 1
  alphaUsage: 1
  alphaIsTransparency: 0
  spriteTessellationDetail: -1
  textureType: 0
  textureShape: 1
  singleChannelComponent: 0
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  platformSettings:
  - serializedVersion: 3
    buildTarget: DefaultTexturePlatform
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Standalone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: iPhone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Android
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
    physicsShape: []
    bones: []
    spriteID:
    internalID: 0
    vertices: []
    indices:
    edges: []
    weights: []
    secondaryTextures: []
  spritePackingTag:
  pSDRemoveMatte: 0
  pSDShowRemoveMatteOption: 0
  userData:
  assetBundleName:
  assetBundleVariant:

repo_name: AlexStrook/ClayxelsPaintingEffect

repo_language: ShaderLab

mime_type: text/plain


text:
fileFormatVersion: 2
guid: cac4d614edb4cba44b064be63161db53
TextureImporter:
  internalIDToNameTable: []
  externalObjects: {}
  serializedVersion: 10
  mipmaps:
    mipMapMode: 0
    enableMipMap: 1
    sRGBTexture: 0
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    mipMapsPreserveCoverage: 0
    alphaTestReferenceValue: 0.5
    mipMapFadeDistanceStart: 1
    mipMapFadeDistanceEnd: 3
  bumpmap:
    convertToNormalMap: 0
    externalNormalMap: 0
    heightScale: 0.25
    normalMapFilter: 0
  isReadable: 0
  streamingMipmaps: 0
  streamingMipmapsPriority: 0
  grayScaleToAlpha: 0
  generateCubemap: 6
  cubemapConvolution: 0
  seamlessCubemap: 0
  textureFormat: 1
  maxTextureSize: 2048
  textureSettings:
    serializedVersion: 2
    filterMode: -1
    aniso: 2
    mipBias: -100
    wrapU: -1
    wrapV: -1
    wrapW: -1
  nPOTScale: 1
  lightmap: 0
  compressionQuality: 50
  spriteMode: 0
  spriteExtrude: 1
  spriteMeshType: 1
  alignment: 0
  spritePivot: {x: 0.5, y: 0.5}
  spritePixelsToUnits: 100
  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
  spriteGenerateFallbackPhysicsShape: 1
  alphaUsage: 1
  alphaIsTransparency: 0
  spriteTessellationDetail: -1
  textureType: 0
  textureShape: 1
  singleChannelComponent: 0
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  platformSettings:
  - serializedVersion: 3
    buildTarget: DefaultTexturePlatform
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Standalone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: iPhone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Android
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: WebGL
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
    physicsShape: []
    bones: []
    spriteID:
    internalID: 0
    vertices: []
    indices:
    edges: []
    weights: []
    secondaryTextures: []
  spritePackingTag:
  pSDRemoveMatte: 0
  pSDShowRemoveMatteOption: 0
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: b82ed60a5ac4a9b478324bb06f9bf242
TextureImporter:
  internalIDToNameTable: []
  externalObjects: {}
  serializedVersion: 10
  mipmaps:
    mipMapMode: 0
    enableMipMap: 1
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    mipMapsPreserveCoverage: 0
    alphaTestReferenceValue: 0.5
    mipMapFadeDistanceStart: 1
    mipMapFadeDistanceEnd: 3
  bumpmap:
    convertToNormalMap: 0
    externalNormalMap: 0
    heightScale: 0.25
    normalMapFilter: 0
  isReadable: 0
  streamingMipmaps: 0
  streamingMipmapsPriority: 0
  grayScaleToAlpha: 0
  generateCubemap: 6
  cubemapConvolution: 0
  seamlessCubemap: 0
  textureFormat: 1
  maxTextureSize: 2048
  textureSettings:
    serializedVersion: 2
    filterMode: -1
    aniso: 2
    mipBias: -100
    wrapU: -1
    wrapV: -1
    wrapW: -1
  nPOTScale: 1
  lightmap: 0
  compressionQuality: 50
  spriteMode: 0
  spriteExtrude: 1
  spriteMeshType: 1
  alignment: 0
  spritePivot: {x: 0.5, y: 0.5}
  spritePixelsToUnits: 100
  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
  spriteGenerateFallbackPhysicsShape: 1
  alphaUsage: 1
  alphaIsTransparency: 0
  spriteTessellationDetail: -1
  textureType: 0
  textureShape: 1
  singleChannelComponent: 0
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  platformSettings:
  - serializedVersion: 3
    buildTarget: DefaultTexturePlatform
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Standalone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: iPhone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Android
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
    physicsShape: []
    bones: []
    spriteID:
    internalID: 0
    vertices: []
    indices:
    edges: []
    weights: []
    secondaryTextures: []
  spritePackingTag:
  pSDRemoveMatte: 0
  pSDShowRemoveMatteOption: 0
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 7e9d69d52b87a9040ac471634a493bbc
TextureImporter:
  internalIDToNameTable: []
  externalObjects: {}
  serializedVersion: 10
  mipmaps:
    mipMapMode: 0
    enableMipMap: 1
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    mipMapsPreserveCoverage: 0
    alphaTestReferenceValue: 0.5
    mipMapFadeDistanceStart: 1
    mipMapFadeDistanceEnd: 3
  bumpmap:
    convertToNormalMap: 0
    externalNormalMap: 0
    heightScale: 0.25
    normalMapFilter: 0
  isReadable: 0
  streamingMipmaps: 0
  streamingMipmapsPriority: 0
  grayScaleToAlpha: 0
  generateCubemap: 6
  cubemapConvolution: 0
  seamlessCubemap: 0
  textureFormat: 1
  maxTextureSize: 2048
  textureSettings:
    serializedVersion: 2
    filterMode: -1
    aniso: 2
    mipBias: -100
    wrapU: -1
    wrapV: -1
    wrapW: -1
  nPOTScale: 1
  lightmap: 0
  compressionQuality: 50
  spriteMode: 0
  spriteExtrude: 1
  spriteMeshType: 1
  alignment: 0
  spritePivot: {x: 0.5, y: 0.5}
  spritePixelsToUnits: 100
  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
  spriteGenerateFallbackPhysicsShape: 1
  alphaUsage: 1
  alphaIsTransparency: 0
  spriteTessellationDetail: -1
  textureType: 0
  textureShape: 1
  singleChannelComponent: 0
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  platformSettings:
  - serializedVersion: 3
    buildTarget: DefaultTexturePlatform
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Standalone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: iPhone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Android
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
    physicsShape: []
    bones: []
    spriteID:
    internalID: 0
    vertices: []
    indices:
    edges: []
    weights: []
    secondaryTextures: []
  spritePackingTag:
  pSDRemoveMatte: 0
  pSDShowRemoveMatteOption: 0
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 9812d8b03e7714344b499b68c6705204
TextureImporter:
  internalIDToNameTable: []
  externalObjects: {}
  serializedVersion: 10
  mipmaps:
    mipMapMode: 0
    enableMipMap: 1
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    mipMapsPreserveCoverage: 0
    alphaTestReferenceValue: 0.5
    mipMapFadeDistanceStart: 1
    mipMapFadeDistanceEnd: 3
  bumpmap:
    convertToNormalMap: 0
    externalNormalMap: 0
    heightScale: 0.25
    normalMapFilter: 0
  isReadable: 0
  streamingMipmaps: 0
  streamingMipmapsPriority: 0
  grayScaleToAlpha: 0
  generateCubemap: 6
  cubemapConvolution: 0
  seamlessCubemap: 0
  textureFormat: 1
  maxTextureSize: 2048
  textureSettings:
    serializedVersion: 2
    filterMode: -1
    aniso: 2
    mipBias: -100
    wrapU: -1
    wrapV: -1
    wrapW: -1
  nPOTScale: 1
  lightmap: 0
  compressionQuality: 50
  spriteMode: 0
  spriteExtrude: 1
  spriteMeshType: 1
  alignment: 0
  spritePivot: {x: 0.5, y: 0.5}
  spritePixelsToUnits: 100
  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
  spriteGenerateFallbackPhysicsShape: 1
  alphaUsage: 1
  alphaIsTransparency: 0
  spriteTessellationDetail: -1
  textureType: 0
  textureShape: 1
  singleChannelComponent: 0
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  platformSettings:
  - serializedVersion: 3
    buildTarget: DefaultTexturePlatform
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Standalone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: iPhone
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  - serializedVersion: 3
    buildTarget: Android
    maxTextureSize: 8192
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 0
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
    physicsShape: []
    bones: []
    spriteID:
    internalID: 0
    vertices: []
    indices:
    edges: []
    weights: []
    secondaryTextures: []
  spritePackingTag:
  pSDRemoveMatte: 0
  pSDShowRemoveMatteOption: 0
  userData:
  assetBundleName:
  assetBundleVariant:


text:
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
 advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
 address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
 professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at mbianchi@mitre.org. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

repo_name: CVEProject/cve-services

repo_language: JavaScript

file_name: Dockerfile


text:
# Contributing to CVE Services

Thank you for considering contributions to the CVE Project's Automation Working Group!

The following is a set of guidelines for contributing. In general, use your best judgement, and feel free to propose changes to this document in a pull request.

#### Table Of Contents

[Code of Conduct](#code-of-conduct)

[I just have a question!!!](#i-just-have-a-question)

[What should I know before I get started?](#what-should-i-know-before-i-get-started)

[How Can I Contribute?](#how-can-i-contribute)

  * [Reporting Bugs](#reporting-bugs)
  * [Pull Requests](#pull-requests)

[Style Guides](#style-guides)

  * [Git Commit Messages](#git-commit-messages)
  * [JavaScript Style Guide](#javascript-style-guide)

[Additional Notes](#additional-notes)
  * [Issue and Pull Request Labels](#issue-and-pull-request-labels)

## Code of Conduct

Contributors to this project are governed by the [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior via email to the AWG Chair at rbritton@mitre.org.

## I just have a question

>**Note:**
>Please don't file an issue to ask a question. Chat is the fastest way to get an answer.

Join the CVE Services Slack channel - email the AWG Chair, rbritton@mitre.org.

## How Can I Contribute?

### Reporting Bugs

This section guides you through submitting a bug report. Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports.

Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](https://github.com/CVEProject/cve-services/blob/dev/.github/ISSUE_TEMPLATE/bug_report.md), the information it asks for helps us resolve issues faster.

>**Note:**
> If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.

#### Before Submitting A Bug Report

**Perform a [cursory search](https://github.com/CVEProject/cve-services/issues?q=is%3Aopen+is%3Aissue+label%3Abug)** to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one.

#### How Do I Submit A (Good) Bug Report?

Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). Provide the following information by filling in [the template](https://github.com/CVEProject/cve-services/blob/dev/.github/ISSUE_TEMPLATE/bug_report.md).

Explain the problem and include additional details to help maintainers reproduce the problem:

* **Use a clear and descriptive title** for the issue to identify the problem.
* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started Atom, e.g. which command exactly you used in the terminal, or how you started Atom otherwise. When listing steps, **don't just say what you did, but explain how you did it**. For example, if you moved the cursor to the end of a line, explain if you used the mouse, or a keyboard shortcut or an Atom command, and if so which one?
* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.
* **Explain which behavior you expected to see instead and why.**
* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below.

Provide more context by answering these questions:

* **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens.

Include details about your configuration and environment:

* **Which version of the API are you using?**
* **What's the name and version of the OS you're using**?

### Code Proposals
This section guides you through submitting a code proposal for CVE services, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your proposal and find related suggestions.

Before creating a code proposal, please check [this list](https://github.com/CVEProject/cve-services/issues?q=is%3Aopen+is%3Aissue+label%3A%22code+proposal%22) as you might find out that you don't need to create one. When you are creating a code proposal, please fill in [the template](https://github.com/CVEProject/cve-services/blob/dev/.github/ISSUE_TEMPLATE/feature_request.md), including the steps that you imagine you would take if the feature you're requesting existed.

#### How Do I Submit A (Good) Code Proposal?

Enhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/). Please make sure to provide the following information:

* **Use a clear and descriptive title** for the issue to identify the suggestion.
* **Provide a step-by-step description of the suggested enhancement** in as many details as possible.
* **Provide specific examples to demonstrate the steps when applicable**. Include copy/paste-able snippets which you use in those examples, as [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
* **Describe the current behavior** and **explain which behavior you expected to see instead** and why (if applicable).
* **Explain why this enhancement would be useful** to most users and isn't something that can or should be implemented as an outside service that just integrates with the API.

### Pull Requests

The process described here has several goals:

- Maintain quality
- Fix problems that are important to users
- Engage the community in working toward the best possible solutions
- Enable a sustainable system for maintainers to review contributions

Please follow these steps to have your contribution considered by the maintainers:

1. Follow the instructions in [the template](PULL_REQUEST_TEMPLATE.md)
2. Follow the [style guides](#style-guides)
3. After you submit a pull request, verify that all [status checks](https://help.github.com/articles/about-status-checks/) pass What if the status checks fail?If a status check fails and you believe that the failure is unrelated to your change, please leave a comment explaining why. If the failure was a false positive, a reviewer will open an issue to track that problem with the status check suite.

>**Note**
> A reviewer may ask you to complete additional design work, tests, or other changes before your pull request is accepted.

## Style Guides

### Git Commit Messages

* Begin the message with the issue number, for example: "#123 this is the commit message". (Git CLI users should specify the message as a flag: `git commit -m "#123 message"` or change the [core.commentchar](https://git-scm.com/docs/git-config#Documentation/git-config.txt-corecommentChar) value.)
* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less

### JavaScript Style Guide

All JavaScript must adhere to [JavaScript Standard Style](https://standardjs.com/).


text:
# Security Policy

- [Reporting a Vulnerability](#reporting-a-vulnerability)
- [Scope](#scope)
- [Fixes](#fixes)
- [Coordination](#coordination)

## Reporting a Vulnerability

Please report security vulnerabilities by going to the [CVE Program web forms](https://cveform.mitre.org/). Please include vulnerability details, steps to reproduce (e.g., proof-of-concept code, screenshots) and an assessment of the impact in your report. We appreciate concise and high quality reports.

#### Web Form Guide

- In the “Select a request type” drop down menu, please select “other”
- Enter your email address in the space provided
- You may enter a PGP key if you prefer to encrypt your correspondence
- In the “Type of comment” drop down menu, please select “Issue”
- In the textbox labeled “Please provide your question, issue, comment, etc.” please start the message with the following information:
  - First Line: “CVE Service Security Anomaly Report”
  - Second Line:  “Distribution: CVE Service Development Team”
  - Third Line: "Description:  [Free Text description of the anomaly]”
- Enter the Security code
- Click “Submit Request”

## Scope

The services in the [CVE Services repository](https://github.com/CVEProject/cve-services) repository are in scope for reporting vulnerabilities.

## Fixes

We will release fixes and assign CVE IDs for verified security vulnerabilities. We expect to publish vulnerabilities using GitHub [security advisories](https://github.com/CVEProject/cve-services/security/advisories).

## Coordination

We appreciate the opportunity to investigate and develop fixes before public disclosure, following coordinated vulnerability disclosure practices.

For vulnerabilities that affect upstream dependencies, we can assist reporting and coordinating with the appropriate parties. We will not share your identification without your permission, but may share the other relevant parts of your report.


text:
Note: Please format the pull request title like:
"Resolves issue ###, High level description of pull request."

Closes Issue ###

# Summary
Write out a concise summary of this MR.

# Important Changes
`example_file.js`
- Cleaned code and added comments.
- Added method to handle adding items.

# Testing

Steps to manually test updated functionality, if possible
- [ ] 1) Example test step.

# Notes
- Some additional notes about this MR.


text:
# Upload 5.0 records
# Global variables should be set appropiately, and a directory of json 5.0 files must be given
import sys
import getopt
import os.path
import json
import requests

RSUS_URL = ''
CVE_API_USER = ''
CVE_API_KEY = ''
CVE_API_ORG = ''

def main(argv):
    inputPath = ''
    try:
        opts, args = getopt.getopt(argv, "hi:", ["ifile="])
    except getopt.GetopError:
        print ('USAGE python cve4to5up.py -i <inputdirectory')
        sys.exit(2)
    for opt, arg in opts:
        if opt == '-h':
            sys.exit()
        elif opt in ("-i", "--ifile"):
            inputPath = arg
    if inputPath:
        for subdir, dirs, files in os.walk(inputPath):
            for file in files:
                with open(inputPath + '/' + file) as json_file:
                    data = json.load(json_file)
                    cve_id = data.get('cveMetadata', {}).get('id')
                    params = {'id': cve_id}
                    headers = {'CVE-API-USER': CVE_API_USER,
                        'CVE-API-ORG': CVE_API_ORG,
                        'CVE-API-KEY': CVE_API_KEY,
                        'Content-Type': "application/json"}
                    r = requests.put(
                        RSUS_URL + cve_id,
                        headers=headers,
                        data=json.dumps(data)
                    )

if __name__ == "__main__":
   main(sys.argv[1:])


text:
# CVE-API

![CodeQL](https://github.com/CVEProject/cve-services/workflows/CodeQL/badge.svg)

## Table of contents

* [Project](#project)
* [Contributing](#contributing)
   * [Security](#security)
      * [Reporting a Vulnerability](#reporting-a-vulnerability)
* [Development](#development)
   * [Technologies](#technologies)
   * [Style Guidelines](#style-guidelines)
   * [Directory Layout](#directory-layout)
   * [Setup](#setup)
   * [API Documentation](#api-documentation)
   * [Unit Testing](#unit-testing)

## The CVE Services Project

This repository contains services that support the [CVE Program's mission](https://www.cve.org/About/Overview) to "identify, define, and catalog publicly disclosed cybersecurity vulnerabilities."

There are many ways one can assist:

### OSS Contributor

Developers can contribute code directly. Getting started can be as fast as choosing an issue on our [board](https://github.com/CVEProject/cve-services/issues?q=is%3Aissue+is%3Aopen).

Please read our [contributor's guide](https://github.com/CVEProject/cve-services/blob/dev/CONTRIBUTING.md) for more details. We welcome all contributions!

### Working Groups

The CVE project operates as multiple focused working groups. Visit the CVE Website [working groups page](https://www.cve.org/ProgramOrganization/WorkingGroups) for more information.

### Security

#### Reporting a Vulnerability

>**Warning**
>Do not put vulnerability information in a GitHub issue.

Please consult our [SECURITY.md](https://github.com/CVEProject/cve-services/blob/dev/SECURITY.md) for specific instructions on reporting a vulnerability that exists in the CVE Services.

## Development

### Technologies

This project uses or depends on software from

- [NodeJS](https://nodejs.org/)
- [Express](https://github.com/expressjs)
- [MongoDB for locally run instances](https://www.mongodb.com/)
- [Mongoose.js](https://mongoosejs.com)

### Style Guidelines

This project follows the [JavaScript Standard Style](https://github.com/standard/standard).

### Setup

#### Docker

See the Docker README found in the repo here: https://github.com/CVEProject/cve-services/blob/dev/docker/README.md

#### Local Development

>**Warning**
>
>DO NOT use the dev configuration on a public network. The dev environment includes credentials to enable rapid development and is not secure for public deployment.

1. Install required node modules

This assumes `node` 16.14.2 and the latest `npm` are installed.

```sh
cd cve-services
npm install
```

2. Setup and start MongoDB locally

Install MongoDB locally

- https://docs.mongodb.com/manual/administration/install-community/

Download MongoDB Compass (MongoDB GUI)

- https://www.mongodb.com/download-center/compass

Create a `cve_dev` database in Compass. The collections will be automatically created when the API starts storing documents.

You can populate the database with test data using:

```sh
npm run populate:dev
```

3. Start the node application

In order to start a dev environment:

```sh
npm run start:dev
```

### API Documentation

API documentation is generated using [swagger-autogen](https://github.com/davibaltar/swagger-autogen) which ensures that we keep the API specification up to date with any major changes to API routes. Extra information for each API route is defined as a comment in the `index.js` files under the respective controller and all request and response schemas are stored under the `schemas` folder served up by `schemas.controller`.

To ensure you are using the correct API specification the following endpoints can be used:
- [Test Instance](https://cveawg-test.mitre.org/api-docs/)
- [Production](https://cveawg.mitre.org/api-docs/)

Note: The specification file stored in GitHub will only be correct for that branch; there could be differences between branches and production.

If you are developer and want to test changes to the API specification you can generate a specification in one of two ways:

1. Preferred

When you start your local development server using `npm run start:dev` the specification file will be generated. Subsequent changes require reloading the server.

2. Manual

You can use `npm run swagger-autogen` to generate a new specification file.

### Unit Testing

This project uses the following for unit testing

- https://mochajs.org/
- https://www.chaijs.com/

In order to run the unit tests:

```sh
npm run start:test
```


text:
---
name: Bug report
about: Create a report to help us improve

---

<!--

Have you read our Code of Conduct? By filing an Issue, you are expected to comply with it, including treating everyone with respect: https://github.com/CVEProject/CVE-Services/blob/dev/CODE_OF_CONDUCT.md

Do you want to ask a question? Are you looking for support? Visit our message board at (TBD).

-->

### Prerequisites

* [ ] Put an X between the brackets on this line if you have done all of the following:
    * Checked the FAQs on the message board for common solutions: (TBD)
    * Checked that your issue isn't already filed.

### Description

<!-- Description of the issue -->

### Steps to Reproduce

The quickest response will be spurred by providing a Postman json file with the exact request or progression of requests that cause the issue.

If a Postman file cannot be provided:

1. <!-- First Step -->
2. <!-- Second Step -->
3. <!-- and so on… -->

**Expected behavior:**

<!-- What you expect to happen -->

**Actual behavior:**

<!-- What actually happens -->

**Reproduces how often:**

<!-- What percentage of the time does it reproduce? -->

### Versions

<!-- What versions does this affect? -->

### Additional Information

<!-- Any additional information, configuration or data that might be necessary to reproduce the issue. -->


text:
---
name: Feature request
about: Suggest an idea for this project

---

<!--

Have you read the Code of Conduct? By filing an Issue, you are expected to comply with it, including treating everyone with respect: https://github.com/CVEProject/CVE-Services/blob/dev/CODE_OF_CONDUCT.md

Do you want to ask a question? Are you looking for support? Visit our message board at (TBD).

-->

## Summary

<!-- One paragraph explanation of the feature. -->

## Motivation

<!-- Why are we doing this? What use cases does it support? What is the expected outcome? -->

## Describe alternatives you've considered

<!-- A clear and concise description of the alternative solutions you've considered. -->

## Additional context

<!-- Add any other context or screenshots about the feature request here. -->


text:
---
name: User Story
about: Use this template to create user stories for the cve-services project
labels: user story, draft
assignees: mattrbianchi
---

# User Story

# Acceptance Criteria

## Scenario 1

<!--
    Scenario – In the first statement, you’ll have to write the name of the behavior that you’re describing.
    Given – The second statement refers to the beginning stage of the scenario.
    When – The third statement involves a particular action that you want the user to make.
    Then – This is used to describe the outcome of the third statement.
    And – You can use “And” to continue any statement except “Scenario.”
-->

Given:

When:

Then:

And:

# Definition of Done

There is at least one unit test per scenario, proving the expectations of the scenario have been met.

There is at least one endpoint (black box) test per scenario, proving the code fulfills the scenario with the application set up similar to its production state.

The openapi.yml file has been updated to document proper use of the new endpoint.
This includes:

	- Describing how different roles can interact with the system when applicable.
	- Successful response
	- Possible error responses


text:
name: "Docker latest"

on:
  pull_request:
    branches: [staging] # This workflow will run when a PR is merged or when a commit is made directly to these branches.
    # NOTE: We want to create a "latest" Github package on changes to `dev`.

jobs:
  build-and-push-image:
    name: Push Docker image to GitHub Packages
    runs-on: ubuntu-latest
    # we can run tests here, and require that they pass
    # but tests should pass on the pull request used to kick this job off,
    # unless we allow changes to `dev` or `release` branches without PRs
    # needs: npm-run-tests
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v2
    - name: Log in to GCR
      run: |
        docker login docker.pkg.github.com \
          --username ${{ github.actor }} \
          --password ${{ secrets.GITHUB_TOKEN }}
    - name: Build Docker latest image
      run: |
        docker build \
        --file docker/Dockerfile \
        --tag docker.pkg.github.com/cveproject/cve-services/cveservices-staging:latest .
    - name: Push Docker latest image to GCR
      run: docker push docker.pkg.github.com/cveproject/cve-services/cveservices-staging:latest


text:
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"

on:
  push:
    branches: [dev, int, master, release*]
  pull_request:
    # The branches below must be a subset of the branches above
  schedule:
    - cron: '0 11 * * 3'

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        # Override automatic language detection by changing the below list
        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
        language: ['javascript']
        # Learn more...
        # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection

    steps:
    - name: Checkout repository
      uses: actions/checkout@v2

    # Initializes the CodeQL tools for scanning.
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v1
      with:
        languages: ${{ matrix.language }}
        # If you wish to specify custom queries, you can do so here or in a config file.
        # By default, queries listed here will override any specified in a config file.
        # Prefix the list here with "+" to use these queries and those in the config file.
        # queries: ./path/to/local/query, your-org/your-repo/queries@main

    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
    # If this step fails, then you should remove it and run the build manually (see below)
    - name: Autobuild
      uses: github/codeql-action/autobuild@v1

    # ℹ Command-line programs to run using the OS shell.
    # 📚 https://git.io/JvXDl

    # ✏ If the Autobuild fails above, remove it and uncomment the following three lines
    #    and modify them (or add more) to build your code if your project
    #    uses a compiled language

    #- run: |
    #   make bootstrap
    #   make release

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v1


text:
name: "Test"

on:
  pull_request:

jobs:
  unit-tests:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x]

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm run action:test

  coverage:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x]

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm run action:coverage


text:
name: "Black Box Testing"

# run this on a pull request for testing
on:
  pull_request:

# use a single job at first
jobs:
  run-functional-tests:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v2
    - name: Build and Run Services and Mongo Containers
      run: |
        cp docker/.docker-env.example docker/.docker-env
        docker-compose --file docker/docker-compose.yml build
        docker-compose --file docker/docker-compose.yml up -d
    - name: Build Test Container
      run: |
        cp test-http/docker/.docker-env.example test-http/docker/.docker-env
        docker-compose --file test-http/docker/docker-compose.yml build
    - name: Run Test Container
      run: |
        docker-compose --file test-http/docker/docker-compose.yml up -d
    - name: Sleep
      run: bash -c "while ! docker-compose --file docker/docker-compose.yml logs --tail=10 cveawg | grep -q 'Serving on port'; do sleep 1; done"
    - name: Load Data into MongoDb
      run: docker-compose -f docker/docker-compose.yml exec -T cveawg npm run populate:dev y
    - name: Run Black Box Tests
      run: |
        docker-compose --file test-http/docker/docker-compose.yml exec -T demon pytest src/ | tee test-http/src/testOutput.txt
    - name: Archive Test Results
      uses: actions/upload-artifact@v2
      with:
        name: test-results
        path: test-http/src/testOutput.txt
        retention-days: 1
    - name: Extract Tests Results
      run: docker-compose --file test-http/docker/docker-compose.yml exec -T demon /bin/bash src/parse_tests_output.sh | (read foo; echo "##[set-output name=result;]$(echo $foo)")
      id: tests_result
    - name: Evaluate Tests Results
      if: ${{ steps.tests_result.outputs.result == 'Tests failed' }}
      run: exit 1


text:
name: "Docker release"

on:
  release:
    types: [published]
  # NOTE: We want to create a "release" Github package when creating actual releases in GitHub.

jobs:
  build-and-push-image:
    name: Push Docker image to GitHub Packages
    runs-on: ubuntu-latest
    # we can run tests here, and require that they pass
    # but tests should pass on the pull request used to kick this job off,
    # unless we allow changes to `dev` or `release` branches without PRs
    # needs: npm-run-tests
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v2
    - name: Extract tag name
      run: echo "##[set-output name=tag;]$(echo ${GITHUB_REF#refs/tags/})"
      id: extract_tag
    - name: Log in to GCR
      run: |
        docker login docker.pkg.github.com \
          --username ${{ github.actor }} \
          --password ${{ secrets.GITHUB_TOKEN }}
    - name: Build Docker release image
      run: |
        docker build \
        --file docker/Dockerfile \
        --tag docker.pkg.github.com/cveproject/cve-services/cveservices-${{ steps.extract_tag.outputs.tag }}:release .
    - name: Push Docker release image to GCR
      run: docker push docker.pkg.github.com/cveproject/cve-services/cveservices-${{ steps.extract_tag.outputs.tag }}:release


text:
name: "Docker latest"

on:
  push:
    branches: [dev] # This workflow will run when a PR is merged or when a commit is made directly to these branches.
    # NOTE: We want to create a "latest" Github package on changes to `dev`.

jobs:
  build-and-push-image:
    name: Push Docker image to GitHub Packages
    runs-on: ubuntu-latest
    # we can run tests here, and require that they pass
    # but tests should pass on the pull request used to kick this job off,
    # unless we allow changes to `dev` or `release` branches without PRs
    # needs: npm-run-tests
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v2
    - name: Log in to GCR
      run: |
        docker login docker.pkg.github.com \
          --username ${{ github.actor }} \
          --password ${{ secrets.GITHUB_TOKEN }}
    - name: Build Docker latest image
      run: |
        docker build \
        --file docker/Dockerfile \
        --tag docker.pkg.github.com/cveproject/cve-services/cveservices-dev:latest .
    - name: Push Docker latest image to GCR
      run: docker push docker.pkg.github.com/cveproject/cve-services/cveservices-dev:latest


text:
on:
  issues:
    types: [opened]
jobs:
  createCard:
    runs-on: ubuntu-latest
    steps:
      - name: Add New Issues to Issue Triage Board
        uses: peter-evans/create-or-update-project-card@866533e2ae61f13c35fd1d374049713fab43c729 # current tag: v2
        with:
          project-name: Issue Triage
          column-name: Needs Triage


text:
name: "Node Integration Tests"

# run this on a pull request for testing
on:
  pull_request:

# use a single job at first
jobs:
  run-integration-tests:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v2
    - name: Build and Run Services and Mongo Containers
      run: |
        cp docker/.docker-env.test-example docker/.docker-env
        docker-compose --file docker/docker-compose.yml build
        docker-compose --file docker/docker-compose.yml up -d
    - name: Sleep
      run: bash -c "while ! docker-compose --file docker/docker-compose.yml logs --tail=10 cveawg | grep -q 'Serving on port'; do sleep 1; done"
    - name: Run Tests
      run: docker-compose -f docker/docker-compose.yml exec -T cveawg npm run test:integration
      continue-on-error: false


text:
name: "Lint"

on:
  pull_request:

jobs:
  lint-src:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x]

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm run action:lint-src

  lint-test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x]

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm run action:lint-test

  lint-test-utils:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x]

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm run action:lint-test-utils


text:
require('dotenv').config() // This enables us to read from the .env file.
const cors = require('cors')
const config = require('config')
const express = require('express')
const app = express()
const helmet = require('helmet')
const mongoose = require('mongoose')
const morgan = require('morgan')

const configureRoutes = require('./routes.config')
const dbUtils = require('./utils/db')
const errors = require('./utils/error')
const logger = require('./middleware/logger')
const mw = require('./middleware/middleware')

const error = new errors.IDRError()

if (process.env.NODE_ENV === 'development') {
  // Concise output colored by response status for development use.
  app.use(morgan('dev'))
  app.use((req, res, next) => {
    res.set({
      'X-Server': 'CVE-Services-Dev-REST-API',
      'X-Server-Type': 'REST'
    })
    next()
  })
} else {
  // Standard Apache common log output.
  app.use(morgan('combined'))
}

app.use(cors())
app.use(helmet()) // Provides standard security <https://www.npmjs.com/package/helmet>
app.use(mw.setCacheControl)
app.use(express.json({ limit: '3.8mb', inflate: false })) // Limit request body size and disable compressed bodies
app.use(express.urlencoded({ extended: true, inflate: false })) // Allows us to handle url encoded dat
app.use('/api/', mw.createCtxAndReqUUID)
global.mongoose = mongoose // Make mongoose connection available globally
configureRoutes(app) // Define api routes
app.use(mw.validateJsonSyntax) // error handler for large input and JSON syntax
app.use(mw.errorHandler) // error handler middleware

// Handle 404 - Keep this as a last route
app.use((req, res, next) => {
  res.status(404).json(error.notFound())
})

// Connect to MongoDB database
const dbConnectionStr = dbUtils.getMongoConnectionString()
mongoose.connect(dbConnectionStr, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useFindAndModify: false,
  useCreateIndex: true
})

// database connection
const db = mongoose.connection

db.on('error', () => {
  console.error.bind(console, 'Connection Error: Something went wrong!')
  logger.error(error.connectionError())
})

db.once('open', () => {
  // we're connected!
  logger.info('Successfully connected to database!')

  // Our testing envrionent sometimes stands up a short lived instance of the app.
  // This can cause breaks if there is already and instance running.
  // A different port is used when running our testing environment through ci to avoid port collisions.
  const port = process.env.NODE_ENV === 'test' ? process.env.TEST_PORT || config.get('port') : process.env.PORT || config.get('port')
  app.listen(port, () => logger.info(`Serving on port ${port}`))
})

module.exports = app


text:
const swaggerUi = require('swagger-ui-express')
const openApiSpecification = require('../api-docs/openapi.json')

const CveController = require('./controller/cve.controller')
const OrgController = require('./controller/org.controller')
const CveIdController = require('./controller/cve-id.controller')
const SchemasController = require('./controller/schemas.controller')
const SystemController = require('./controller/system.controller')
const UserController = require('./controller/user.controller')

var options = {
  swaggerOptions: {
    url: '/api-docs/openapi.json'
  }
}

// Hide try-out related elements and update some parameter display CSS
var setupOptions = {
  customCss: `.swagger-ui .try-out { display: none }
              .swagger-ui .parameters-col_description input { display: none }
              .swagger-ui .parameters-col_description select { display: none }
              .swagger-ui .parameter__in { font-weight: bold; color: black }
              .swagger-ui .parameters-col_name { width: 20% }
              .swagger-ui .renderedMarkdown a {text-decoration: none;}`
}

module.exports = async function configureRoutes (app) {
  app.use('/api/', CveController)
  app.use('/api/', OrgController)
  app.use('/api/', CveIdController)
  app.use('/api/', SystemController)
  app.use('/api/', UserController)
  app.get('/api-docs/openapi.json', (req, res) => res.json(openApiSpecification))
  app.use('/api-docs', swaggerUi.serveFiles(null, options), swaggerUi.setup(null, setupOptions))
  app.use('/schemas/', SchemasController)
}


text:
const swaggerAutogen = require('swagger-autogen')({ openapi: '3.0.2' })
const outputFile = 'api-docs/openapi.json'
const endpointsFiles = [
  'src/controller/cve-id.controller/index.js',
  'src/controller/cve.controller/index.js',
  'src/controller/org.controller/index.js',
  'src/controller/user.controller/index.js',
  'src/controller/system.controller/index.js'
]
const publishedCVERecord = require('../schemas/cve/published-cve-example.json')
const rejectedCVERecord = require('../schemas/cve/rejected-cve-example.json')
const rejectedCreateCVERecord = require('../schemas/cve/rejected-create-cve-example.json')

/* eslint-disable no-multi-str */
const doc = {
  info: {
    version: '2.2.0',
    title: 'CVE Services API',
    description: "The CVE Services API supports automation tooling for the CVE Program. Credentials are \
    required for most service endpoints. Representatives of \
    CVE Numbering Authorities (CNAs) should \
    use one of the methods below to obtain credentials:\

If your organization already has an Organizational Administrator (OA) account for the CVE \
    Services, ask your admin for credentials
 \

Contact your Root (Google, \
    INCIBE, \
    JPCERT/CC, or \
    Red Hat) or \
    Top-Level Root (CISA ICS \
    or MITRE) to request credentials \

 \

CVE data is to be in the JSON 5.0 CVE Record format. Details of the JSON 5.0 schema are \
    located here.
\
    Contact the CVE Services team",
    contact: {
      name: 'CVE Services Overview',
      url: 'https://cveproject.github.io/automation-cve-services#services-overview'

    }
  },
  servers: [
    {
      url: 'urlplaceholder'
    }
  ],
  basePath: '/api',
  host: 'localhost:3000',
  schemes: [
    'https'
  ],
  components: {
    parameters: {
      active: {
        in: 'query',
        name: 'active',
        description: 'The new active state for the user entry.  Accepted values are 1, true, or yes to indicate true, and 0, false, or no to indicate false',
        required: false,
        schema: {
          type: 'boolean'
        }
      },
      active_roles_add: {
        in: 'query',
        name: 'active_roles.add',
        description: 'Add an active role to the organization',
        required: false,
        schema: {
          type: 'string',
          enum: [
            'CNA',
            'SECRETARIAT'
          ]
        }
      },
      active_roles_remove: {
        in: 'query',
        name: 'active_roles.remove',
        description: 'Remove an active role from the organization',
        required: false,
        schema: {
          type: 'string',
          enum: [
            'CNA',
            'SECRETARIAT'
          ]
        }
      },
      activeUserRolesAdd: {
        in: 'query',
        name: 'active_roles.add',
        description: 'Add an active role to the user',
        required: false,
        schema: {
          type: 'string',
          enum: [
            'ADMIN'
          ]
        }
      },
      activeUserRolesRemove: {
        in: 'query',
        name: 'active_roles.remove',
        description: 'Remove an active role from the user',
        required: false,
        schema: {
          type: 'string',
          enum: [
            'ADMIN'
          ]
        }
      },
      apiEntityHeader: {
        in: 'header',
        name: 'CVE-API-ORG',
        description: 'The shortname for the organization associated with the user requesting authentication',
        required: true,
        schema: {
          type: 'string'
        }
      },
      apiUserHeader: {
        in: 'header',
        name: 'CVE-API-USER',
        description: 'The username for the account making the request',
        required: true,
        schema: {
          type: 'string'
        }
      },
      apiSecretHeader: {
        in: 'header',
        name: 'CVE-API-KEY',
        description: 'The user\'s API key',
        required: true,
        schema: {
          type: 'string'
        }
      },
      amount: {
        in: 'query',
        name: 'amount',
        description: 'Quantity of CVE IDs to reserve',
        required: true,
        schema: {
          type: 'integer',
          format: 'int32'
        }
      },
      assigner: {
        in: 'query',
        name: 'assigner',
        description: 'Filter by assigner org UUID',
        required: false,
        schema: {
          type: 'string'
        }
      },
      assignerShortName: {
        in: 'query',
        name: 'assigner_short_name',
        description: 'Filter by assignerShortName',
        required: false,
        schema: {
          type: 'string'
        }
      },
      batch_type: {
        in: 'query',
        name: 'batch_type',
        description: 'Required when amount is greater than one, determines whether the reserved CVE IDs should be sequential or non-sequential',
        required: false,
        schema: {
          type: 'string',
          enum: [
            'sequential',
            'non-sequential',
            'nonsequential'
          ]
        }
      },
      countOnly: {
        in: 'query',
        name: 'count_only',
        description: 'Get count of records that match query. Accepted values are 1, true, or yes to indicate true, and 0, false, or no to indicate false',
        required: false,
        schema: {
          type: 'boolean'
        }
      },
      nextPage: {
        in: 'query',
        name: 'next_page',
        description: 'Key returned by a GET /cve_cursor call that must be used to get the next page of results in a subsequent call',
        required: false,
        schema: {
          type: 'string'
        }
      },
      previousPage: {
        in: 'query',
        name: 'previous_page',
        description: 'Key returned by a GET /cve_cursor call that must be used to get the previous page of results in a subsequent call',
        required: false,
        schema: {
          type: 'string'
        }
      },
      limit: {
        in: 'query',
        name: 'limit',
        description: 'CVE records to return per page. Must be between 1-500. ',
        required: false,
        schema: {
          type: 'integer'
        }
      },
      cnaModified: {
        in: 'query',
        name: 'cna_modified',
        description: 'Only get CVE records with cnaContainers that have been modified/created within the set time_modified range. Requires at least one time_modified parameter set',
        required: false,
        schema: {
          type: 'boolean'
        }
      },
      adpShortName: {
        in: 'query',
        name: 'adp_short_name',
        description: 'Only get CVE records that have an adpContainer owned by this org.',
        required: false,
        schema: {
          type: 'string'
        }
      },
      cveState: {
        in: 'query',
        name: 'state',
        description: 'Filter by state',
        schema: {
          type: 'string',
          enum: [
            'PUBLISHED',
            'REJECTED'
          ]
        }
      },
      cve_year: {
        in: 'query',
        name: 'cve_year',
        description: 'The year the CVE IDs will be reserved for (i.e., 1999, ..., currentYear + 1)',
        required: true,
        schema: {
          type: 'integer',
          format: 'int32'
        }
      },
      cveIdGetFilteredState: {
        in: 'query',
        name: 'state',
        description: 'Filter by state ',
        required: false,
        schema: {
          type: 'string',
          enum: [
            'RESERVED',
            'PUBLISHED',
            'REJECTED'
          ]
        }
      },
      cveIdGetFilteredCveIdYear: {
        in: 'query',
        name: 'cve_id_year',
        description: 'Filter by the year of the CVE IDs',
        required: false,
        schema: {
          type: 'string'

        }
      },
      cveIdGetFilteredTimeReservedLt: {
        in: 'query',
        name: 'time_reserved.lt',
        description: 'Most recent reserved timestamp to retrieve. Include with all requests potentially returning multiple pages of CVE IDs to avoid issues if new IDs are reserved during use.

 Timestamp format : yyyy-MM-ddTHH:mm:ssZZZZ',
        required: false,
        schema: {
          type: 'string',
          format: 'date-time'
        }
      },
      cveIdGetFilteredTimeReservedGt: {
        in: 'query',
        name: 'time_reserved.gt',
        description: 'Earliest CVE ID reserved timestamp to retrieve

 Timestamp format : yyyy-MM-ddTHH:mm:ssZZZZ',
        required: false,
        schema: {
          type: 'string',
          format: 'date-time'
        }
      },
      cveIdGetFilteredTimeModifiedLt: {
        in: 'query',
        name: 'time_modified.lt',
        description: 'Most recent modified timestamp to retrieve. Include with all requests using a time_modified.gt filter potentially returning multiple pages of CVE IDs. This will avoid issues if IDs are reserved or modified during use.

 Timestamp format : yyyy-MM-ddTHH:mm:ssZZZZ',
        required: false,
        schema: {
          type: 'string',
          format: 'date-time'
        }
      },
      cveIdGetFilteredTimeModifiedGt: {
        in: 'query',
        name: 'time_modified.gt',
        description: 'Earliest CVE ID modified timestamp to retrieve

 Timestamp format : yyyy-MM-ddTHH:mm:ssZZZZ',
        required: false,
        schema: {
          type: 'string',
          format: 'date-time'
        }
      },
      cveRecordFilteredTimeModifiedLt: {
        in: 'query',
        name: 'time_modified.lt',
        description: 'Most recent CVE record modified timestamp to retrieve

 Timestamp format : yyyy-MM-ddTHH:mm:ssZZZZ',
        required: false,
        schema: {
          type: 'string',
          format: 'date-time'
        }
      },
      cveRecordFilteredTimeModifiedGt: {
        in: 'query',
        name: 'time_modified.gt',
        description: 'Earliest CVE record modified timestamp to retrieve

 Timestamp format : yyyy-MM-ddTHH:mm:ssZZZZ',
        required: false,
        schema: {
          type: 'string',
          format: 'date-time'
        }
      },
      id_quota: {
        in: 'query',
        name: 'id_quota',
        description: 'The new number of CVE IDs the organization is allowed to have in the RESERVED state at one time',
        required: false,
        schema: {
          type: 'integer',
          format: 'int32',
          minimum: 0,
          maximum: 100000
        }
      },
      name: {
        in: 'query',
        name: 'name',
        description: 'The new name for the organization',
        required: false,
        schema: {
          type: 'string'
        }
      },
      nameFirst: {
        in: 'query',
        name: 'name.first',
        description: 'The new first name for the user entry',
        required: false,
        schema: {
          type: 'string'
        }
      },
      nameLast: {
        in: 'query',
        name: 'name.last',
        description: 'The new last name for the user entry',
        required: false,
        schema: {
          type: 'string'
        }
      },
      nameMiddle: {
        in: 'query',
        name: 'name.middle',
        description: 'The new middle name for the user entry',
        required: false,
        schema: {
          type: 'string'
        }
      },
      nameSuffix: {
        in: 'query',
        name: 'name.suffix',
        description: 'The new suffix for the user entry',
        required: false,
        schema: {
          type: 'string'
        }
      },
      newShortname: {
        in: 'query',
        name: 'new_short_name',
        description: 'The new shortname for the organization',
        required: false,
        schema: {
          type: 'string'
        }
      },
      newUsername: {
        in: 'query',
        name: 'new_username',
        description: 'The new username for the user, preferably the user\'s email address. Must be 3-128 characters in length; allowed characters are alphanumeric and -_@.',
        required: false,
        schema: {
          type: 'string'
        }
      },
      org: {
        in: 'query',
        name: 'org',
        description: 'The shortname of the new owning_cna for the CVE ID',
        required: false,
        schema: {
          type: 'string'
        }
      },
      orgShortname: {
        in: 'query',
        name: 'org_short_name',
        description: 'The new organization for the user',
        required: false,
        schema: {
          type: 'string'
        }
      },
      pageQuery: {
        in: 'query',
        name: 'page',
        description: 'The current page in the paginator',
        required: false,
        schema: {
          type: 'integer',
          format: 'int32',
          minimum: 1
        }
      },
      short_name: {
        in: 'query',
        name: 'short_name',
        description: 'The CNA that will own the reserved CVE IDs',
        required: true,
        schema: {
          type: 'string'
        }
      },
      shortname: {
        in: 'query',
        name: 'shortname',
        description: 'The new shortname for the organization',
        required: false,
        schema: {
          type: 'string'
        }
      },
      state: {
        in: 'query',
        name: 'state',
        description: 'The new state for the CVE ID',
        required: false,
        schema: {
          type: 'string',
          enum: [
            'RESERVED',
            'REJECTED'
          ]
        }
      }
    },
    examples: {
      publishedRecord: publishedCVERecord,
      rejectedRecord: rejectedCVERecord,
      rejectedCreateCVERecord: rejectedCreateCVERecord
    }
  }
}

swaggerAutogen(outputFile, endpointsFiles, doc)


text:
const BaseRepository = require('./baseRepository')
const Cve = require('../model/cve')

class CveRepository extends BaseRepository {
  constructor () {
    super(Cve)
  }

  async findOneByCveId (id) {
    const results = this.collection.findOne().byCveId(id)
    return results
  }

  async updateByCveId (id, cve, options = {}) {
    return this.collection.findOneAndUpdate().byCveId(id).updateOne(cve).setOptions(options)
  }
}

module.exports = CveRepository


text:
const BaseRepository = require('./baseRepository')
const User = require('../model/user')
const utils = require('../utils/utils')

class UserRepository extends BaseRepository {
  constructor () {
    super(User)
  }

  async getUserUUID (userName, orgUUID) {
    return utils.getUserUUID(userName, orgUUID)
  }

  async isAdmin (username, shortname) {
    return utils.isAdmin(username, shortname)
  }

  async isAdminUUID (username, orgUUID) {
    return utils.isAdminUUID(username, orgUUID)
  }

  async findOneByUUID (UUID) {
    return this.collection.findOne().byUUID(UUID)
  }

  async findUsersByOrgUUID (orgUUID) {
    return this.collection.find().byOrgUUID(orgUUID).countDocuments().exec()
  }

  async findOneByUserNameAndOrgUUID (userName, orgUUID) {
    return this.collection.findOne().byUserNameAndOrgUUID(userName, orgUUID)
  }

  async updateByUserNameAndOrgUUID (username, orgUUID, user, options = {}) {
    return this.collection.findOneAndUpdate().byUserNameAndOrgUUID(username, orgUUID).updateOne(user).setOptions(options)
  }

  async getAllUsers () {
    return this.collection.find()
  }
}

module.exports = UserRepository


text:
const BaseRepository = require('./baseRepository')
const CveIdRange = require('../model/cve-id-range')

class CveIdRangeRepository extends BaseRepository {
  constructor () {
    super(CveIdRange)
  }
}

module.exports = CveIdRangeRepository


text:
const OrgRepository = require('./orgRepository')
const CveRepository = require('./cveRepository')
const CveIdRepository = require('./cveIdRepository')
const CveIdRangeRepository = require('./cveIdRangeRepository')
const UserRepository = require('./userRepository')

class RepositoryFactory {
  getOrgRepository () {
    const repo = new OrgRepository()
    return repo
  }

  getCveRepository () {
    const repo = new CveRepository()
    return repo
  }

  getCveIdRepository () {
    const repo = new CveIdRepository()
    return repo
  }

  getCveIdRangeRepository () {
    const repo = new CveIdRangeRepository()
    return repo
  }

  getUserRepository () {
    const repo = new UserRepository()
    return repo
  }
}

module.exports = RepositoryFactory


text:
// baseRepository for Mongoose
const mongoose = require('mongoose')

class BaseRepository {
  constructor (model) {
    this.mongoose = mongoose
    if (typeof model === 'string') {
      this.collection = mongoose.model(model)
    } else {
      this.collection = model
    }
  }

  async aggregate (aggregation) {
    return this.collection.aggregate(aggregation)
  }

  async aggregatePaginate (aggregation, options) {
    const arg = this.collection.aggregate(aggregation)
    return this.collection.aggregatePaginate(arg, options)
  }

  async cursorPaginate (query, limit, next, previous, paginatedField) {
    return this.collection.paginate({ query, limit: Number(limit), previous, next, paginatedField: paginatedField })
  }

  async find (query = {}, { multiple = true, count, lean, limit } = {}) {
    const results = multiple ? this.collection.find(query) : this.collection.findOne(query)

    if (count) {
      return results.countDocuments().exec()
    } else if (lean) {
      return results.lean().exec()
    } else if (limit) {
      return results.limit(limit).exec()
    } else {
      return results.exec()
    }
  }

  async findOne (query = {}) {
    const results = this.collection.findOne(query)
    return results.exec()
  }

  async findOneAndUpdate (query = {}, set = {}, options = {}) {
    return this.collection.findOneAndUpdate(query, set, options)
  }

  async findOneAndReplace (query = {}, replacement = {}) {
    return this.collection.findOneAndReplace(query, replacement)
  }

  async findOneAndRemove (query = {}) {
    return this.collection.findOneAndRemove(query)
  }

  async insertMany (documents) {
    return this.collection.insertMany(documents)
  }

  async countDocuments (query = {}) {
    return this.collection.countDocuments(query)
  }

  async estimatedDocumentCount (query = {}) {
    return this.collection.estimatedDocumentCount(query)
  }

  async deleteMany (query = {}) {
    return this.collection.deleteMany(query)
  }
}

module.exports = BaseRepository


text:
const BaseRepository = require('./baseRepository')
const Org = require('../model/org')
const utils = require('../utils/utils')

class OrgRepository extends BaseRepository {
  constructor () {
    super(Org)
  }

  async findOneByShortName (shortName) {
    return this.collection.findOne().byShortName(shortName)
  }

  async findOneByUUID (UUID) {
    return this.collection.findOne().byUUID(UUID)
  }

  async getOrgUUID (shortName) {
    return utils.getOrgUUID(shortName)
  }

  async updateByOrgUUID (orgUUID, org, options = {}) {
    return this.collection.findOneAndUpdate().byUUID(orgUUID).updateOne(org).setOptions(options)
  }

  async isSecretariat (shortName) {
    return utils.isSecretariat(shortName)
  }

  async isSecretariatUUID (shortName) {
    return utils.isSecretariatUUID(shortName)
  }

  async isBulkDownload (shortName) {
    return utils.isBulkDownload(shortName)
  }

  async getAllOrgs () {
    return this.collection.find()
  }
}

module.exports = OrgRepository


text:
const BaseRepository = require('./baseRepository')
const CveId = require('../model/cve-id')

class CveIdRepository extends BaseRepository {
  constructor () {
    super(CveId)
  }

  async findOneByCveId (id) {
    return this.collection.findOne().byCveId(id)
  }

  async updateByCveId (id, cveIdObj, options = {}) {
    return this.collection.findOneAndUpdate().byCveId(id).updateOne(cveIdObj).setOptions(options)
  }
}

module.exports = CveIdRepository


text:
/*
 * A template for creating additional one-time-use scripts.
 * Example use-cases:
 * 1. migrating documents
 * 2. populating a new MongoDb-compatible database
 * 3. creating a database snapshot
 * 4. ...
 */

const mongoose = require('mongoose')

const dbUtils = require('../utils/db')
const errors = require('../utils/error')
const logger = require('../middleware/logger')

const error = new errors.IDRError()

const dbConnectionStr = dbUtils.getMongoConnectionString()
mongoose.connect(dbConnectionStr, {
  useNewUrlParser: true,
  useUnifiedTopology: false,
  useFindAndModify: false
})

const db = mongoose.connection

db.on('error', () => {
  console.error.bind(console, 'Connection Error: Something went wrong!')
  logger.error(error.connectionError())
})

db.once('open', async () => {
  logger.info('Successfully connected to database!')

  // do stuff here

  mongoose.connection.close()
})


text:
/*
 * used to populate the Cve collection without dropping/updating any other
 * collection
 */

const express = require('express')
const app = express()
const mongoose = require('mongoose')

const dataUtils = require('../utils/data')
const dbUtils = require('../utils/db')
const errors = require('../utils/error')
const logger = require('../middleware/logger')
const Cve = require('../model/cve')

const error = new errors.IDRError()

// Body Parser Middleware
app.use(express.json()) // Allows us to handle raw JSON data
app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data
// Make mongoose connection available globally
global.mongoose = mongoose

// Connect to MongoDB database
const dbConnectionStr = dbUtils.getMongoConnectionString()
mongoose.connect(dbConnectionStr, {
  useNewUrlParser: true,
  useUnifiedTopology: false,
  useFindAndModify: false
})

// database connection
const db = mongoose.connection

db.on('error', () => {
  console.error.bind(console, 'Connection Error: Something went wrong!')
  logger.error(error.connectionError())
})

db.once('open', async () => {
  logger.info('Successfully connected to database!')

  // user needs to agree to an action that drops collections
  const userInput = dataUtils.getUserPopulateInput(['Cve'])

  // dropping Cve collection
  // this may be more complex than necessary, but is kept similar to `src/scripts/populate.js`
  if (userInput.toLowerCase() === 'y') {
    let names = []
    let collections = await db.db.listCollections().toArray()
    collections.forEach(collection => {
      names.push(collection.name)
    })

    if (names.includes('Cve')) {
      await db.dropCollection('Cve')
    }

    names = []
    collections = await db.db.listCollections().toArray()
    collections.forEach(collection => {
      names.push(collection.name)
    })

    if (!names.includes('Cve')) {
      await dataUtils.populateCollection(
        './datadump/pre-population/cves.json',
        Cve
      )
      logger.info('Successfully populated CVE records!')
    } else {
      logger.error(
        'The database was not populated because ' +
        'some of the collections were not deleted.'
      )
    }
  }

  mongoose.connection.close()
})


text:
const replaceInFile = require('replace-in-file')

if (process.env.NODE_ENV === 'development') {
  replaceInFile.sync({
    files: 'api-docs/openapi.json',
    from: 'urlplaceholder',
    to: 'https://cveawg-dev.mitre.org/api'
  })
}

if (process.env.NODE_ENV === 'staging') {
  replaceInFile.sync({
    files: 'api-docs/openapi.json',
    from: 'urlplaceholder',
    to: 'https://cveawg-test.mitre.org/api'
  })
}

if (process.env.NODE_ENV === 'integration') {
  replaceInFile.sync({
    files: 'api-docs/openapi.json',
    from: 'urlplaceholder',
    to: 'https://cveawg-int.mitre.org/api'
  })
}

if (process.env.NODE_ENV === 'production') {
  replaceInFile.sync({
    files: 'api-docs/openapi.json',
    from: 'urlplaceholder',
    to: 'https://cveawg.mitre.org/api'
  })
}


text:
/*
 * used to populate or re-populate a MongoDB-compatible document
 * database with static fixtures at `cve-services/datadump/pre-population`
 */

const express = require('express')
const app = express()
const mongoose = require('mongoose')

const dataUtils = require('../utils/data')
const dbUtils = require('../utils/db')
const errors = require('../utils/error')
const logger = require('../middleware/logger')
const CveIdRange = require('../model/cve-id-range')
const CveId = require('../model/cve-id')
const Cve = require('../model/cve')
const Org = require('../model/org')
const User = require('../model/user')

const error = new errors.IDRError()

const populateTheseCollections = {
  Cve: Cve,
  'Cve-Id-Range': CveIdRange,
  'Cve-Id': CveId,
  User: User,
  Org: Org
}

const indexesToCreate = {
  Cve: [{ 'cve.cveMetadata.cveId': 1 }, { 'cve.cveMetadata.dateUpdated': 1 }],
  'Cve-Id': [{ cve_id: 1 }, { owning_cna: 1, state: 1 }, { reserved: 1 }],
  User: [{ UUID: 1 }],
  Org: [{ UUID: 1 }, { 'authority.active_roles': 1 }]
}

// Body Parser Middleware
app.use(express.json()) // Allows us to handle raw JSON data
app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data
// Make mongoose connection available globally
global.mongoose = mongoose

// Connect to MongoDB database
const dbConnectionStr = dbUtils.getMongoConnectionString()
mongoose.connect(dbConnectionStr, {
  useNewUrlParser: true,
  useUnifiedTopology: false,
  useFindAndModify: false,
  autoIndex: false
})

const db = mongoose.connection

db.on('error', () => {
  console.error.bind(console, 'Connection Error: Something went wrong!')
  logger.error(error.connectionError())
})

db.once('open', async () => {
  logger.info('Successfully connected to database!')

  let userInput
  if (process.argv.length > 2 && process.argv.slice(2)[0] === 'y') {
    userInput = process.argv.slice(2)[0]
  } else {
    // script runner (currently) needs to agree to an action that drops collections
    userInput = dataUtils.getUserPopulateInput(Object.keys(populateTheseCollections))
  }

  // drops and re-populates collections
  if (userInput.toLowerCase() === 'y') {
    let names = []
    let collections = await db.db.listCollections().toArray()
    collections.forEach(collection => {
      names.push(collection.name)
    })

    for (const name in populateTheseCollections) {
      if (names.includes(name)) {
        logger.info(`Dropping ${name} collection indexes!!!`)
        await db.collections[name].dropIndexes()
        logger.info(`Dropping ${name} collection !!!`)
        await db.dropCollection(name)
      }
    }

    names = []
    collections = await db.db.listCollections().toArray()
    collections.forEach(collection => {
      names.push(collection.name)
    })

    if (!names.includes('Cve-Id-Range') && !names.includes('Cve-Id') && !names.includes('Cve') &&
        !names.includes('Org') && !names.includes('User')) {
      // Org
      await dataUtils.populateCollection(
        './datadump/pre-population/orgs.json',
        Org, dataUtils.newOrgTransform
      )

      // User, depends on Org
      const hash = await dataUtils.preprocessUserSecrets()
      await dataUtils.populateCollection(
        './datadump/pre-population/users.json',
        User, dataUtils.newUserTransform, hash
      )

      const populatePromises = []

      // CVE ID Range
      populatePromises.push(dataUtils.populateCollection(
        './datadump/pre-population/cve-ids-range.json',
        CveIdRange
      ))

      // CVE
      if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
        populatePromises.push(dataUtils.populateCollection(
          './datadump/pre-population/cves.json',
          Cve, dataUtils.newCveTransform
        ))
      }

      // CVE ID, depends on User and Org
      populatePromises.push(dataUtils.populateCollection(
        './datadump/pre-population/cve-ids.json',
        CveId, dataUtils.newCveIdTransform
      ))

      // don't close database connection until all remaining populate
      // promises are resolved
      Promise.all(populatePromises).then(function () {
        logger.info('Successfully populated the database!')

        Object.keys(indexesToCreate).forEach(col => {
          indexesToCreate[col].forEach(index => {
            db.collections[col].createIndex(index)
          })
        })
        mongoose.connection.close()
      })
    } else {
      logger.error(
        'The database was not populated because ' +
        'some of the collections were not deleted.'
      )
      mongoose.connection.close()
    }
  } else {
    mongoose.connection.close()
  }
})


text:
const fs = require('fs')
const cveSchemaV5 = JSON.parse(fs.readFileSync('src/middleware/5.0_bundled_schema.json'))

/**
 * Return default values.
 *
 * The object is created in this function to prevent accidental
 * value re-assignment and still allow IDE type-hints and compiled regex
 *
 * @return {defaults}
 */
function getConstants () {
  /**
  * @constant
  * @default
  * @lends defaults
  */
  const defaults = {
    MONGOOSE_VALIDATION: {
      Org_policies_id_quota_min: 0,
      Org_policies_id_quota_min_message: 'Org.policies.id_quota cannot be a negative number.',
      Org_policies_id_quota_max: 100000,
      Org_policies_id_quota_max_message: 'Org.policies.id_quota cannot exceed maximum threshold.'
    },
    DEFAULT_ID_QUOTA: 1000,
    DEFAULT_AVAILABLE_POOL: 100,
    NONSEQUENTIAL_MAX_AMOUNT: 10,
    CRYPTO_RANDOM_STRING_LENGTH: 36,
    AUTH_ROLE_ENUM: {
      SECRETARIAT: 'SECRETARIAT',
      CNA: 'CNA',
      BULK_DOWNLOAD: 'BULK_DOWNLOAD',
      ROOT_CNA: 'ROOT_CNA',
      ADP: 'ADP'
    },
    ORG_ROLES: [
      'CNA',
      'SECRETARIAT',
      'BULK_DOWNLOAD',
      'ROOT_CNA',
      'ADP'
    ],
    USER_ROLES: [
      'ADMIN'
    ],
    USER_ROLE_ENUM: {
      ADMIN: 'ADMIN'
    },
    AUTH_HEADERS: {
      ORG: 'CVE-API-ORG',
      USER: 'CVE-API-USER',
      KEY: 'CVE-API-KEY'
    },
    CVE_STATES: {
      PUBLISHED: 'PUBLISHED',
      RESERVED: 'RESERVED',
      REJECTED: 'REJECTED',
      AVAILABLE: 'AVAILABLE'
    },
    QUOTA_HEADER: 'CVE-API-REMAINING-QUOTA',
    DEFAULT_CVE_ID_RANGE: {
      cve_year: 2020,
      ranges: {
        priority: {
          top_id: 0,
          start: 0,
          end: 20000
        },
        general: {
          top_id: 20000,
          start: 20000,
          end: 50000000
        }
      }
    },
    PAGINATOR_HEADERS: {
      PAGE: 'PAGINATOR-PAGE'
    },
    PAGINATOR_PAGE: 1,
    PAGINATOR_OPTIONS: {
      limit: 500,
      lean: true,
      useFacet: false,
      customLabels: {
        totalDocs: 'itemCount',
        docs: 'itemsList',
        limit: 'itemsPerPage',
        page: 'currentPage',
        totalPages: 'pageCount',
        useFacet: false
      }
    },
    MAX_SHORTNAME_LENGTH: 32,
    MIN_SHORTNAME_LENGTH: 2,
    MAX_FIRSTNAME_LENGTH: 100,
    MAX_LASTNAME_LENGTH: 100,
    MAX_MIDDLENAME_LENGTH: 100,
    MAX_SUFFIX_LENGTH: 100,
    CVE_ID_PATTERN: cveSchemaV5.definitions.cveId.pattern,
    // Ajv's pattern validation uses the "u" (unicode) flag:
    // https://ajv.js.org/json-schema.html#pattern
    CVE_ID_REGEX: new RegExp(cveSchemaV5.definitions.cveId.pattern, 'u')
  }

  return defaults
}

module.exports = {
  getConstants
}


text:
const express = require('express')
const router = express.Router()
const mw = require('../../middleware/middleware')
const { query } = require('express-validator')
const controller = require('./user.controller')
const { parseGetParams, parseError } = require('./user.middleware')
const getConstants = require('../../constants').getConstants
const CONSTANTS = getConstants()

router.get('/users',
  /*
  #swagger.tags = ['Users']
  #swagger.operationId = 'userAll'
  #swagger.summary = "Retrieves information about all registered users (accessible to Secretariat)"
  #swagger.description = "

Access Control

 User must belong to an organization with the Secretariat role

Expected Behavior

Secretariat: Retrieves information about all users for all organizations
"
  #swagger.parameters['$ref'] = [
    '#/components/parameters/pageQuery',
    '#/components/parameters/apiEntityHeader',
    '#/components/parameters/apiUserHeader',
    '#/components/parameters/apiSecretHeader'
  ]
  #swagger.responses[200] = {
    description: 'Returns all users, along with pagination fields if results span multiple pages of data.',
    content:{
      "application/json":{
        schema: { $ref: '../schemas/user/list-users-response.json' }
      }
    }
  }
  #swagger.responses[400] = {
    description: 'Bad Request',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/bad-request.json' }
      }
    }
  }
  #swagger.responses[401] = {
    description: 'Not Authenticated',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' },
      }
    }
  }
  #swagger.responses[403] = {
    description: 'Forbidden',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[404] = {
    description: 'Not Found',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  #swagger.responses[500] = {
    description: 'Internal Server Error',
    content: {
      "application/json": {
        schema: { $ref: '../schemas/errors/generic.json' }
      }
    }
  }
  */
  mw.validateUser,
  mw.onlySecretariat,
  query(['page']).optional().isInt({ min: CONSTANTS.PAGINATOR_PAGE }),
  parseError,
  parseGetParams,
  controller.ALL_USERS)

module.exports = router


text:
require('dotenv').config()
const logger = require('../../middleware/logger')
const getConstants = require('../../constants').getConstants

/**
 * Get the details of all users
 * Called by GET /api/users
**/
async function getAllUsers (req, res, next) {
  try {
    const CONSTANTS = getConstants()

    // temporary measure to allow tests to work after fixing #920
    // tests required changing the global limit to force pagination
    if (req.TEST_PAGINATOR_LIMIT) {
      CONSTANTS.PAGINATOR_OPTIONS.limit = req.TEST_PAGINATOR_LIMIT
    }

    const options = CONSTANTS.PAGINATOR_OPTIONS
    options.sort = { short_name: 'asc' }
    options.page = req.ctx.query.page ? parseInt(req.ctx.query.page) : CONSTANTS.PAGINATOR_PAGE // if 'page' query parameter is not defined, set 'page' to the default page value
    const repo = req.ctx.repositories.getUserRepository()

    const agt = setAggregateUserObj({})
    const pg = await repo.aggregatePaginate(agt, options)
    const payload = { users: pg.itemsList }

    if (pg.itemCount >= CONSTANTS.PAGINATOR_OPTIONS.limit) {
      payload.totalCount = pg.itemCount
      payload.itemsPerPage = pg.itemsPerPage
      payload.pageCount = pg.pageCount
      payload.currentPage = pg.currentPage
      payload.prevPage = pg.prevPage
      payload.nextPage = pg.nextPage
    }

    logger.info({ uuid: req.ctx.uuid, message: 'The user information was sent to the secretariat user.' })
    return res.status(200).json(payload)
  } catch (err) {
    next(err)
  }
}

function setAggregateUserObj (query) {
  return [
    {
      $match: query
    },
    {
      $project: {
        _id: false,
        username: true,
        name: true,
        UUID: true,
        org_UUID: true,
        active: true,
        'authority.active_roles': true,
        time: true
      }
    }
  ]
}

module.exports = {
  ALL_USERS: getAllUsers
}


text:
const idrErr = require('../../utils/error')

class UserControllerError extends idrErr.IDRError {

}

module.exports = {
  UserControllerError
}


text:
const { validationResult } = require('express-validator')
const errors = require('./error')
const error = new errors.UserControllerError()
const utils = require('../../utils/utils')

function parseGetParams (req, res, next) {
  utils.reqCtxMapping(req, 'query', ['page'])
  next()
}

function parseError (req, res, next) {
  const err = validationResult(req).formatWith(({ location, msg, param, value, nestedErrors }) => {
    return { msg: msg, param: param, location: location }
  })
  if (!err.isEmpty()) {
    return res.status(400).json(error.badInput(err.array()))
  }
  next()
}

module.exports = {
  parseGetParams,
  parseError
}