[
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\r\n## files generated by popular Visual Studio add-ons.\r\n##\r\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\r\n\r\n*.exe\r\n\r\n# User-specific files\r\n*.rsuser\r\n*.suo\r\n*.user\r\n*.userosscache\r\n*.sln.docstates\r\n\r\n# User-specific files (MonoDevelop/Xamarin Studio)\r\n*.userprefs\r\n\r\n# Mono auto generated files\r\nmono_crash.*\r\n\r\n# Build results\r\n[Dd]ebug/\r\n[Dd]ebugPublic/\r\n[Rr]elease/\r\n[Rr]eleases/\r\nx64/\r\nx86/\r\n[Ww][Ii][Nn]32/\r\n[Aa][Rr][Mm]/\r\n[Aa][Rr][Mm]64/\r\nbld/\r\n[Bb]in/\r\n[Oo]bj/\r\n[Ll]og/\r\n[Ll]ogs/\r\n\r\n# Visual Studio 2015/2017 cache/options directory\r\n.vs/\r\n# Uncomment if you have tasks that create the project's static files in wwwroot\r\n#wwwroot/\r\n\r\n# Visual Studio 2017 auto generated files\r\nGenerated\\ Files/\r\n\r\n# MSTest test Results\r\n[Tt]est[Rr]esult*/\r\n[Bb]uild[Ll]og.*\r\n\r\n# NUnit\r\n*.VisualState.xml\r\nTestResult.xml\r\nnunit-*.xml\r\n\r\n# Build Results of an ATL Project\r\n[Dd]ebugPS/\r\n[Rr]eleasePS/\r\ndlldata.c\r\n\r\n# Benchmark Results\r\nBenchmarkDotNet.Artifacts/\r\n\r\n# .NET Core\r\nproject.lock.json\r\nproject.fragment.lock.json\r\nartifacts/\r\n\r\n# ASP.NET Scaffolding\r\nScaffoldingReadMe.txt\r\n\r\n# StyleCop\r\nStyleCopReport.xml\r\n\r\n# Files built by Visual Studio\r\n*_i.c\r\n*_p.c\r\n*_h.h\r\n*.ilk\r\n*.meta\r\n*.obj\r\n*.iobj\r\n*.pch\r\n*.pdb\r\n*.ipdb\r\n*.pgc\r\n*.pgd\r\n*.rsp\r\n*.sbr\r\n*.tlb\r\n*.tli\r\n*.tlh\r\n*.tmp\r\n*.tmp_proj\r\n*_wpftmp.csproj\r\n*.log\r\n*.tlog\r\n*.vspscc\r\n*.vssscc\r\n.builds\r\n*.pidb\r\n*.svclog\r\n*.scc\r\n\r\n# Chutzpah Test files\r\n_Chutzpah*\r\n\r\n# Visual C++ cache files\r\nipch/\r\n*.aps\r\n*.ncb\r\n*.opendb\r\n*.opensdf\r\n*.sdf\r\n*.cachefile\r\n*.VC.db\r\n*.VC.VC.opendb\r\n\r\n# Visual Studio profiler\r\n*.psess\r\n*.vsp\r\n*.vspx\r\n*.sap\r\n\r\n# Visual Studio Trace Files\r\n*.e2e\r\n\r\n# TFS 2012 Local Workspace\r\n$tf/\r\n\r\n# Guidance Automation Toolkit\r\n*.gpState\r\n\r\n# ReSharper is a .NET coding add-in\r\n_ReSharper*/\r\n*.[Rr]e[Ss]harper\r\n*.DotSettings.user\r\n\r\n# TeamCity is a build add-in\r\n_TeamCity*\r\n\r\n# DotCover is a Code Coverage Tool\r\n*.dotCover\r\n\r\n# AxoCover is a Code Coverage Tool\r\n.axoCover/*\r\n!.axoCover/settings.json\r\n\r\n# Coverlet is a free, cross platform Code Coverage Tool\r\ncoverage*.json\r\ncoverage*.xml\r\ncoverage*.info\r\n\r\n# Visual Studio code coverage results\r\n*.coverage\r\n*.coveragexml\r\n\r\n# NCrunch\r\n_NCrunch_*\r\n.*crunch*.local.xml\r\nnCrunchTemp_*\r\n\r\n# MightyMoose\r\n*.mm.*\r\nAutoTest.Net/\r\n\r\n# Web workbench (sass)\r\n.sass-cache/\r\n\r\n# Installshield output folder\r\n[Ee]xpress/\r\n\r\n# DocProject is a documentation generator add-in\r\nDocProject/buildhelp/\r\nDocProject/Help/*.HxT\r\nDocProject/Help/*.HxC\r\nDocProject/Help/*.hhc\r\nDocProject/Help/*.hhk\r\nDocProject/Help/*.hhp\r\nDocProject/Help/Html2\r\nDocProject/Help/html\r\n\r\n# Click-Once directory\r\npublish/\r\n\r\n# Publish Web Output\r\n*.[Pp]ublish.xml\r\n*.azurePubxml\r\n# Note: Comment the next line if you want to checkin your web deploy settings,\r\n# but database connection strings (with potential passwords) will be unencrypted\r\n*.pubxml\r\n*.publishproj\r\n\r\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\r\n# checkin your Azure Web App publish settings, but sensitive information contained\r\n# in these scripts will be unencrypted\r\nPublishScripts/\r\n\r\n# NuGet Packages\r\n*.nupkg\r\n# NuGet Symbol Packages\r\n*.snupkg\r\n# The packages folder can be ignored because of Package Restore\r\n[Pp]ackages/*\r\n# except build/, which is used as an MSBuild target.\r\n![Pp]ackages/build/\r\n# Uncomment if necessary however generally it will be regenerated when needed\r\n#!**/[Pp]ackages/repositories.config\r\n# NuGet v3's project.json files produces more ignorable files\r\n*.nuget.props\r\n*.nuget.targets\r\n\r\n# Nuget personal access tokens and Credentials\r\nnuget.config\r\n\r\n# Microsoft Azure Build Output\r\ncsx/\r\n*.build.csdef\r\n\r\n# Microsoft Azure Emulator\r\necf/\r\nrcf/\r\n\r\n# Windows Store app package directories and files\r\nAppPackages/\r\nBundleArtifacts/\r\nPackage.StoreAssociation.xml\r\n_pkginfo.txt\r\n*.appx\r\n*.appxbundle\r\n*.appxupload\r\n\r\n# Visual Studio cache files\r\n# files ending in .cache can be ignored\r\n*.[Cc]ache\r\n# but keep track of directories ending in .cache\r\n!?*.[Cc]ache/\r\n\r\n# Others\r\nClientBin/\r\n~$*\r\n*~\r\n*.dbmdl\r\n*.dbproj.schemaview\r\n*.jfm\r\n*.pfx\r\n*.publishsettings\r\norleans.codegen.cs\r\n\r\n# Including strong name files can present a security risk\r\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\r\n#*.snk\r\n\r\n# Since there are multiple workflows, uncomment next line to ignore bower_components\r\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\r\n#bower_components/\r\n\r\n# RIA/Silverlight projects\r\nGenerated_Code/\r\n\r\n# Backup & report files from converting an old project file\r\n# to a newer Visual Studio version. Backup files are not needed,\r\n# because we have git ;-)\r\n_UpgradeReport_Files/\r\nBackup*/\r\nUpgradeLog*.XML\r\nUpgradeLog*.htm\r\nServiceFabricBackup/\r\n*.rptproj.bak\r\n\r\n# SQL Server files\r\n*.mdf\r\n*.ldf\r\n*.ndf\r\n\r\n# Business Intelligence projects\r\n*.rdl.data\r\n*.bim.layout\r\n*.bim_*.settings\r\n*.rptproj.rsuser\r\n*- [Bb]ackup.rdl\r\n*- [Bb]ackup ([0-9]).rdl\r\n*- [Bb]ackup ([0-9][0-9]).rdl\r\n\r\n# Microsoft Fakes\r\nFakesAssemblies/\r\n\r\n# GhostDoc plugin setting file\r\n*.GhostDoc.xml\r\n\r\n# Node.js Tools for Visual Studio\r\n.ntvs_analysis.dat\r\nnode_modules/\r\n\r\n# Visual Studio 6 build log\r\n*.plg\r\n\r\n# Visual Studio 6 workspace options file\r\n*.opt\r\n\r\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\r\n*.vbw\r\n\r\n# Visual Studio LightSwitch build output\r\n**/*.HTMLClient/GeneratedArtifacts\r\n**/*.DesktopClient/GeneratedArtifacts\r\n**/*.DesktopClient/ModelManifest.xml\r\n**/*.Server/GeneratedArtifacts\r\n**/*.Server/ModelManifest.xml\r\n_Pvt_Extensions\r\n\r\n# Paket dependency manager\r\n.paket/paket.exe\r\npaket-files/\r\n\r\n# FAKE - F# Make\r\n.fake/\r\n\r\n# CodeRush personal settings\r\n.cr/personal\r\n\r\n# Python Tools for Visual Studio (PTVS)\r\n__pycache__/\r\n*.pyc\r\n\r\n# Cake - Uncomment if you are using it\r\n# tools/**\r\n# !tools/packages.config\r\n\r\n# Tabs Studio\r\n*.tss\r\n\r\n# Telerik's JustMock configuration file\r\n*.jmconfig\r\n\r\n# BizTalk build output\r\n*.btp.cs\r\n*.btm.cs\r\n*.odx.cs\r\n*.xsd.cs\r\n\r\n# OpenCover UI analysis results\r\nOpenCover/\r\n\r\n# Azure Stream Analytics local run output\r\nASALocalRun/\r\n\r\n# MSBuild Binary and Structured Log\r\n*.binlog\r\n\r\n# NVidia Nsight GPU debugger configuration file\r\n*.nvuser\r\n\r\n# MFractors (Xamarin productivity tool) working folder\r\n.mfractor/\r\n\r\n# Local History for Visual Studio\r\n.localhistory/\r\n\r\n# BeatPulse healthcheck temp database\r\nhealthchecksdb\r\n\r\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\r\nMigrationBackup/\r\n\r\n# Ionide (cross platform F# VS Code tools) working folder\r\n.ionide/\r\n\r\n# Fody - auto-generated XML schema\r\nFodyWeavers.xsd\r\n\r\n# VS Code files for those working on multiple tools\r\n.vscode/*\r\n!.vscode/settings.json\r\n!.vscode/tasks.json\r\n!.vscode/launch.json\r\n!.vscode/extensions.json\r\n*.code-workspace\r\n\r\n# Local History for Visual Studio Code\r\n.history/\r\n\r\n# Windows Installer files from build outputs\r\n*.cab\r\n*.msi\r\n*.msix\r\n*.msm\r\n*.msp\r\n\r\n# JetBrains Rider\r\n.idea/\r\n*.sln.iml"
  },
  {
    "path": "Detections/SCMKit.rules",
    "content": "alert tcp $HOME_NET any -> any $HTTP_PORTS (flow:established,to_server; content:\"SCMKIT-5dc493ada400c79dd318abbe770dac7c\"; http_header; fast_pattern:only; pcre:\"/^User\\x2dAgent\\x3a\\x20SCMKit/Hm\"; metadata:service http; msg:\"Known malicious user-agent string SCMKit tool\"; id:5493400793187707; rev:1; )\n"
  },
  {
    "path": "Detections/SCMKit.yar",
    "content": "rule SCMKit_Signatures\n{\n    meta:\n        description = \"Static signatures for the SCMKit tool.\"\n        md5 = \"9b4b2a06aa840afcbbfe2d412f99b4a8\"\n        rev = 1\n        author = \"Brett Hawkins\"\n    strings:\n        $typelibguid = \"266c644a-69b1-426b-a47c-1cf32b211f80\" ascii nocase wide\n        $gitlabModules = \"SCMKit.modules.gitlab\" ascii nocase wide\n        $githubModules = \"SCMKit.modules.github\" ascii nocase wide\n        $bitbucketModules = \"SCMKit.modules.bitbucket\" ascii nocase wide\n    condition:\n        uint16(0) == 0x5A4D and $typelibguid and $gitlabModules and $githubModules and $bitbucketModules\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2022 Brett Hawkins\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# SCMKit\n\n## Description\n**S**ource **C**ode **M**anagement Attack Tool**kit** - SCMKit is a toolkit that can be used to attack SCM systems. SCMKit allows the user to specify the SCM system and attack module to use, along with specifying valid credentials (username/password or API key) to the respective SCM system. Currently, the SCM systems that SCMKit supports are GitHub Enterprise, GitLab Enterprise and Bitbucket Server. The attack modules supported include reconnaissance, privilege escalation and persistence. SCMKit was built in a modular approach, so that new modules and SCM systems can be added in the future by the information security community.\n\n## Release\n* Version 1.2 of SCMKit can be found in Releases\n\n## Table of Contents\n\n- [SCMKit](#scmkit)\n- [Table of Contents](#table-of-contents)\n- [Installation/Building](#installationbuilding)\n  - [Libraries Used](#libraries-used)\n  - [Pre-Compiled](#pre-compiled)\n  - [Building Yourself](#building-yourself)\n- [Usage](#usage)\n  - [Arguments/Options](#argumentsoptions)\n  - [Systems](#systems--s--system)\n  - [Modules](#modules--m--module)\n  - [Module Details Table](#Module-Details-Table)\n- [Examples](#examples)\n  - [List Repos](#List-repos)\n  - [Search Repos](#Search-repos)\n  - [Search Code](#Search-code)\n  - [Search Files](#Search-files)\n  - [List Snippets](#List-snippets)\n  - [List Runners](#List-runners)\n  - [List Gists](#List-gists)\n  - [List Orgs](#List-orgs)\n  - [Get Privileges of API Key](#Get-privileges-of-api-token)\n  - [Add Admin](#Add-admin)\n  - [Remove Admin](#Remove-admin)\n  - [Create Access Token](#Create-access-token)\n  - [List Access Tokens](#List-access-tokens)\n  - [Remove Access Token](#Remove-access-token)\n  - [Create SSH Key](#Create-ssh-key)\n  - [List SSH Keys](#List-ssh-keys)\n  - [Remove SSH Key](#Remove-ssh-key)\n  - [List Admin Stats](#list-admin-stats)\n  - [List Branch Protection](#list-branch-protection)\n- [Detection](#detection)\n- [References](#references)\n\n\n## Installation/Building\n\n### Libraries Used\nThe below 3rd party libraries are used in this project.\n\n| Library | URL | License |\n| ------------- | ------------- | ------------- |\n| Octokit  | [https://github.com/octokit/octokit.net](https://github.com/octokit/octokit.net) | MIT License  |\n| Fody  | [https://github.com/Fody/Fody](https://github.com/Fody/Fody) | MIT License  |\n| GitLabApiClient  | [https://github.com/nmklotas/GitLabApiClient](https://github.com/nmklotas/GitLabApiClient) | MIT License  |\n| Newtonsoft.Json  | [https://github.com/JamesNK/Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) | MIT License  |\n\n### Pre-Compiled \n\n* Use the pre-compiled binary in Releases\n\n### Building Yourself\n\nTake the below steps to setup Visual Studio in order to compile the project yourself. This requires a .NET library that can be installed from the NuGet package manager.\n\n\n* Load the Visual Studio project up and go to \"Tools\" --> \"NuGet Package Manager\" --> \"Package Manager Settings\"\n* Go to \"NuGet Package Manager\" --> \"Package Sources\"\n* Add a package source with the URL `https://api.nuget.org/v3/index.json`\n* Install the below NuGet packages\n  * `Install-Package Costura.Fody -Version 3.3.3`\n  * `Install-Package Octokit`\n  * `Install-Package GitLabApiClient`\n  * `Install-Package Newtonsoft.Json`\n* You can now build the project yourself!\n\n## Usage\n\n### Arguments/Options\n\n* <b>-c, -credential </b> - credential for authentication (username:password or apiKey)\n* <b>-s, -system </b> - system to attack (github,gitlab,bitbucket)\n* <b>-u, -url </b> - URL for GitHub Enterprise, GitLab Enterprise or Bitbucket Server\n* <b>-m, -module </b> - module to run\n* <b>-o, -option </b> - options (when applicable)\n\n### Systems (-s, -system)\n* <b>github:</b> GitHub Enterprise\n* <b>gitlab:</b> GitLab Enterprise\n* <b>bitbucket:</b> Bitbucket Server\n\n### Modules (-m, -module)\n* <b>listrepo:</b> list all repos the current user can see\n* <b>searchrepo:</b> search for a given repo\n* <b>searchcode:</b> search for code containing keyword search term\n* <b>searchfile:</b> search for filename containing keyword search term\n* <b>listsnippet:</b> list all snippets of current user\n* <b>listrunner:</b> list all GitLab runners available to current user\n* <b>listgist:</b> list all gists of current user\n* <b>listorg:</b> list all orgs current user belongs to\n* <b>privs:</b> get privs of current API token\n* <b>addadmin:</b> promote given user to admin role\n* <b>removeadmin:</b> demote given user from admin role\n* <b>createpat:</b> create personal access token for target user\n* <b>listpat:</b> list personal access tokens for a target user\n* <b>removepat:</b> remove personal access token for a target user\n* <b>createsshkey:</b> create SSH key for current user\n* <b>listsshkey:</b> list SSH keys for current user\n* <b>removesshkey:</b> remove SSH key for current user\n* <b>adminstats:</b> get admin stats (users, repos, orgs, gists)\n* <b>protection:</b> get branch protection settings\n\n\n\n### Module Details Table\nThe below table shows where each module is supported\n\nAttack Scenario | Module  | Requires Admin? | GitHub Enterprise | GitLab Enterprise | Bitbucket Server\n:---: |:---: | :---: | :---: | :---: | :---:\nReconnaissance | `listrepo` |  No | X | X | X\nReconnaissance |`searchrepo` |  No | X | X | X\nReconnaissance |`searchcode` |  No | X | X | X\nReconnaissance |`searchfile` |  No | X | X | X\nReconnaissance |`listsnippet` |  No |  | X | \nReconnaissance |`listrunner` |  No |  | X | \nReconnaissance |`listgist` |  No | X |  | \nReconnaissance |`listorg` |  No | X |  | \nReconnaissance |`privs` |  No | X | X | \nReconnaissance |`protection` |  No | X |  | \nPersistence | `listsshkey` |  No | X | X | X\nPersistence | `removesshkey` |  No | X | X | X\nPersistence | `createsshkey` |  No | X | X | X\nPersistence | `listpat` |  No |  | X | X\nPersistence | `removepat` |  No |  | X | X\nPersistence | `createpat` |  Yes (GitLab Enterprise only) |  | X | X\nPrivilege Escalation | `addadmin` |  Yes | X | X | X\nPrivilege Escalation | `removeadmin` |  Yes | X | X | X\nReconnaissance | `adminstats` |  Yes | X |  |\n\n\n## Examples\n\n### List Repos\n\n#### Use Case\n\n> *Discover repositories being used in a particular SCM system*\n\n#### Syntax\n\nProvide the `listrepo` module, along with any relevant authentication information and URL. This will output the repository name and URL.\n\n##### GitHub Enterprise\n\nThis will list all repositories that a user can see.\n\n`SCMKit.exe -s github -m listrepo -c userName:password -u https://github.something.local`\n\n`SCMKit.exe -s github -m listrepo -c apiKey -u https://github.something.local`\n\n##### GitLab Enterprise\n\nThis will list all repositories that a user can see.\n\n`SCMKit.exe -s gitlab -m listrepo -c userName:password -u https://gitlab.something.local`\n\n`SCMKit.exe -s gitlab -m listrepo -c apiKey -u https://gitlab.something.local`\n\n##### Bitbucket Server\n\nThis will list all repositories that a user can see.\n\n`SCMKit.exe -s bitbucket -m listrepo -c userName:password -u https://bitbucket.something.local`\n\n`SCMKit.exe -s bitbucket -m listrepo -c apiKey -u https://bitbucket.something.local`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m listrepo -c username:password -u https://gitlab.hogwarts.local\n\n==================================================\nModule:         listrepo\nSystem:         gitlab\nAuth Type:      Username/Password\nOptions:\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      1/14/2022 8:30:47 PM\n==================================================\n\n                                    Name | Visibility |                                                URL\n----------------------------------------------------------------------------------------------------------\n                            MaraudersMap |    Private | https://gitlab.hogwarts.local/hpotter/maraudersmap\n                            testingStuff |   Internal | https://gitlab.hogwarts.local/adumbledore/testingstuff\n                               Spellbook |   Internal |    https://gitlab.hogwarts.local/hpotter/spellbook\n       findShortestPathToGryffindorSword |   Internal | https://gitlab.hogwarts.local/hpotter/findShortestPathToGryffindorSword\n                                  charms |     Public |      https://gitlab.hogwarts.local/hgranger/charms\n                           Secret-Spells |   Internal | https://gitlab.hogwarts.local/adumbledore/secret-spells\n                              Monitoring |   Internal | https://gitlab.hogwarts.local/gitlab-instance-10590c85/Monitoring\n```\n\n### Search Repos\n\n#### Use Case\n\n> *Search for repositories by repository name in a particular SCM system*\n\n#### Syntax\n\nProvide the `searchrepo` module and your search criteria in the `-o` command-line switch, along with any relevant authentication information and URL. This will output the matching repository name and URL.\n\n##### GitHub Enterprise\n\nThe GitHub repo search is a \"contains\" search where the string you enter it will search for repos with names that contain your search term.\n\n`SCMKit.exe -s github -m searchrepo -c userName:password -u https://github.something.local -o \"some search term\"`\n\n`SCMKit.exe -s github -m searchrepo -c apikey -u https://github.something.local -o \"some search term\"`\n\n##### GitLab Enterprise\n\nThe GitLab repo search is a \"contains\" search where the string you enter it will search for repos with names that contain your search term.\n\n`SCMKit.exe -s gitlab -m searchrepo -c userName:password -u https://gitlab.something.local -o \"some search term\"`\n\n`SCMKit.exe -s gitlab -m searchrepo -c apikey -u https://gitlab.something.local -o \"some search term\"`\n\n##### Bitbucket Server\n\nThe Bitbucket repo search is a \"starts with\" search where the string you enter it will search for repos with names that start with your search term.\n\n`SCMKit.exe -s bitbucket -m searchrepo -c userName:password -u https://bitbucket.something.local -o \"some search term\"`\n\n`SCMKit.exe -s bitbucket -m searchrepo -c apikey -u https://bitbucket.something.local -o \"some search term\"`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m searchrepo -c apiKey -u https://gitlab.hogwarts.local -o \"spell\"\n\n==================================================\nModule:         searchrepo\nSystem:         gitlab\nAuth Type:      API Key\nOptions:        spell\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      1/14/2022 8:32:30 PM\n==================================================\n\n                                    Name | Visibility |                                                URL\n----------------------------------------------------------------------------------------------------------\n                               Spellbook |   Internal |    https://gitlab.hogwarts.local/hpotter/spellbook\n                           Secret-Spells |   Internal | https://gitlab.hogwarts.local/adumbledore/secret-spells\n```\n\n### Search Code\n\n#### Use Case\n\n> *Search for code containing a given keyword in a particular SCM system*\n\n#### Syntax\n\nProvide the `searchcode` module and your search criteria in the `-o` command-line switch, along with any relevant authentication information and URL. This will output the URL to the matching code file, along with the line in the code that matched.\n\n##### GitHub Enterprise\n\nThe GitHub code search is a \"contains\" search where the string you enter it will search for code that contains your search term in any line.\n\n`SCMKit.exe -s github -m searchcode -c userName:password -u https://github.something.local -o \"some search term\"`\n\n`SCMKit.exe -s github -m searchcode -c apikey -u https://github.something.local -o \"some search term\"`\n\n##### GitLab Enterprise\n\nThe GitLab code search is a \"contains\" search where the string you enter it will search for code that contains your search term in any line.\n\n`SCMKit.exe -s gitlab -m searchcode -c userName:password -u https://gitlab.something.local -o \"some search term\"`\n\n`SCMKit.exe -s gitlab -m searchcode -c apikey -u https://gitlab.something.local -o \"some search term\"`\n\n##### Bitbucket Server\n\nThe Bitbucket code search is a \"contains\" search where the string you enter it will search for code that contains your search term in any line.\n\n`SCMKit.exe -s bitbucket -m searchcode -c userName:password -u https://bitbucket.something.local -o \"some search term\"`\n\n`SCMKit.exe -s bitbucket -m searchcode -c apikey -u https://bitbucket.something.local -o \"some search term\"`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m searchcode -c username:password -u https://gitlab.hogwarts.local -o \"api_key\"\n\n==================================================\nModule:         searchcode\nSystem:         gitlab\nAuth Type:      Username/Password\nOptions:        api_key\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      1/14/2022 8:34:14 PM\n==================================================\n\n\n[>] URL: https://gitlab.hogwarts.local/adumbledore/secret-spells/stuff.txt\n    |_ API_KEY=abc123\n\nTotal number of items matching code search: 1\n\n```\n\n### Search Files\n\n#### Use Case\n\n> *Search for files in repositories containing a given keyword in the file name in a particular SCM system*\n\n#### Syntax\n\nProvide the `searchfile` module and your search criteria in the `-o` command-line switch, along with any relevant authentication information and URL. This will output the URL to the matching file in its respective repository.\n\n##### GitHub Enterprise\n\nThe GitLab file search is a \"contains\" search where the string you enter it will search for files that contains your search term in the file name.\n\n`SCMKit.exe -s github -m searchfile -c userName:password -u https://github.something.local -o \"some search term\"`\n\n`SCMKit.exe -s github -m searchfile -c apikey -u https://github.something.local -o \"some search term\"`\n\n##### GitLab Enterprise\n\nThe GitLab file search is a \"contains\" search where the string you enter it will search for files that contains your search term in the file name.\n\n`SCMKit.exe -s gitlab -m searchfile -c userName:password -u https://gitlab.something.local -o \"some search term\"`\n\n`SCMKit.exe -s gitlab -m searchfile -c apikey -u https://gitlab.something.local -o \"some search term\"`\n\n##### Bitbucket Server\n\nThe Bitbucket file search is a \"contains\" search where the string you enter it will search for files that contains your search term in the file name.\n\n`SCMKit.exe -s bitbucket -m searchfile -c userName:password -u https://bitbucket.something.local -o \"some search term\"`\n\n`SCMKit.exe -s bitbucket -m searchfile -c apikey -u https://bitbucket.something.local -o \"some search term\"`\n\n#### Example Output\n\n```\n\nC:\\source\\SCMKit\\SCMKit\\bin\\Release>SCMKit.exe -s bitbucket -m searchfile -c apikey -u http://bitbucket.hogwarts.local:7990 -o jenkinsfile\n\n==================================================\nModule:         searchfile\nSystem:         bitbucket\nAuth Type:      API Key\nOptions:        jenkinsfile\nTarget URL:     http://bitbucket.hogwarts.local:7990\n\nTimestamp:      1/14/2022 10:17:59 PM\n==================================================\n\n\n[>] REPO: http://bitbucket.hogwarts.local:7990/scm/~HPOTTER/hpotter\n    [>] FILE: Jenkinsfile\n\n[>] REPO: http://bitbucket.hogwarts.local:7990/scm/STUD/cred-decryption\n    [>] FILE: subDir/Jenkinsfile\n\nTotal matching results: 2\n\n```\n\n### List Snippets\n\n#### Use Case\n\n> *List snippets owned by the current user in GitLab*\n\n#### Syntax\n\nProvide the `listsnippet` module, along with any relevant authentication information and URL.\n\n##### GitLab Enterprise\n\n`SCMKit.exe -s gitlab -m listsnippet -c userName:password -u https://gitlab.something.local`\n\n`SCMKit.exe -s gitlab -m listsnippet -c apikey -u https://gitlab.something.local`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m listsnippet -c username:password -u https://gitlab.hogwarts.local\n\n==================================================\nModule:         listsnippet\nSystem:         gitlab\nAuth Type:      Username/Password\nOptions:\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      1/14/2022 9:17:36 PM\n==================================================\n\n               Title |                                                                Raw URL\n---------------------------------------------------------------------------------------------\n        spell-script |                         https://gitlab.hogwarts.local/-/snippets/2/raw\n```\n\n### List Runners\n\n#### Use Case\n\n> *List all GitLab runners available to the current user in GitLab*\n\n#### Syntax\n\nProvide the `listrunner` module, along with any relevant authentication information and URL. If the user is an administrator, you will be able to list all runners within the GitLab Enterprise instance, which includes shared and group runners. \n\n##### GitLab Enterprise\n\n`SCMKit.exe -s gitlab -m listrunner -c userName:password -u https://gitlab.something.local`\n\n`SCMKit.exe -s gitlab -m listrunner -c apikey -u https://gitlab.something.local`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m listrunner -c username:password -u https://gitlab.hogwarts.local\n\n==================================================\nModule:         listrunner\nSystem:         gitlab\nAuth Type:      Username/Password\nOptions:\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      1/25/2022 11:40:08 AM\n==================================================\n\n   ID |                 Name |                                      Repo Assigned\n---------------------------------------------------------------------------------\n    2 |        gitlab-runner | https://gitlab.hogwarts.local/hpotter/spellbook.git\n    3 |        gitlab-runner | https://gitlab.hogwarts.local/hpotter/maraudersmap.git\n    \n```\n\n\n### List Gists\n\n#### Use Case\n\n> *List gists owned by the current user in GitHub*\n\n#### Syntax\n\nProvide the `listgist` module, along with any relevant authentication information and URL.\n\n##### GitHub Enterprise\n\n`SCMKit.exe -s github -m listgist -c userName:password -u https://github.something.local`\n\n`SCMKit.exe -s github -m listgist -c apikey -u https://github.something.local`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s github -m listgist -c username:password -u https://github-enterprise.hogwarts.local\n\n==================================================\nModule:         listgist\nSystem:         github\nAuth Type:      Username/Password\nOptions:\nTarget URL:     https://github-enterprise.hogwarts.local\n\nTimestamp:      1/14/2022 9:43:23 PM\n==================================================\n\n                             Description | Visibility |                                                URL\n----------------------------------------------------------------------------------------------------------\n            Shell Script to Decode Spell |     public | https://github-enterprise.hogwarts.local/gist/c11c6bb3f47fe67183d5bc9f048412a1\n            \n```\n\n### List Orgs\n\n#### Use Case\n\n> *List all organizations the current user belongs to in GitHub*\n\n#### Syntax\n\nProvide the `listorg` module, along with any relevant authentication information and URL.\n\n##### GitHub Enterprise\n\n`SCMKit.exe -s github -m listorg -c userName:password -u https://github.something.local`\n\n`SCMKit.exe -s github -m listorg -c apiKey -u https://github.something.local`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s github -m listorg -c username:password -u https://github-enterprise.hogwarts.local\n\n==================================================\nModule:         listorg\nSystem:         github\nAuth Type:      Username/Password\nOptions:\nTarget URL:     https://github-enterprise.hogwarts.local\n\nTimestamp:      1/14/2022 9:44:48 PM\n==================================================\n\n                          Name |                                                URL\n-----------------------------------------------------------------------------------\n                      Hogwarts | https://github-enterprise.hogwarts.local/api/v3/orgs/Hogwarts/repos\n                      \n```\n\n### Get Privileges of API Token\n\n#### Use Case\n\n> *Get the assigned privileges to an access token being used in a particular SCM system*\n\n#### Syntax\n\nProvide the `privs` module, along with an API key and URL.\n\n##### GitHub Enterprise\n\n`SCMKit.exe -s github -m privs -c apiKey -u https://github.something.local`\n\n##### GitLab Enterprise\n\n`SCMKit.exe -s gitlab -m privs -c apiKey -u https://gitlab.something.local`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m privs -c apikey -u https://gitlab.hogwarts.local\n\n==================================================\nModule:         privs\nSystem:         gitlab\nAuth Type:      API Key\nOptions:\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      1/14/2022 9:18:27 PM\n==================================================\n\n          Token Name |    Active? |            Privilege |                                                            Description\n---------------------------------------------------------------------------------------------------------------------------------\n  hgranger-api-token |       True |                  api | Read-write for the complete API, including all groups and projects, the Container Registry, and the Package Registry.\n  hgranger-api-token |       True |            read_user | Read-only for endpoints under /users. Essentially, access to any of the GET requests in the Users API.\n  hgranger-api-token |       True |             read_api | Read-only for the complete API, including all groups and projects, the Container Registry, and the Package Registry.\n  hgranger-api-token |       True |      read_repository |                      Read-only (pull) for the repository through git clone.\n  hgranger-api-token |       True |     write_repository | Read-write (pull, push) for the repository through git clone. Required for accessing Git repositories over HTTP when 2FA is enabled.\n  \n```\n\n### Add Admin\n\n#### Use Case\n\n> *Promote a normal user to an administrative role in a particular SCM system*\n\n#### Syntax\n\nProvide the `addadmin` module, along with any relevant authentication information and URL. Additionally, provide the target user you would like to add an administrative role to.\n\n##### GitHub Enterprise\n\n`SCMKit.exe -s github -m addadmin -c userName:password -u https://github.something.local -o targetUserName`\n\n`SCMKit.exe -s github -m addadmin -c apikey -u https://github.something.local -o targetUserName`\n\n##### GitLab Enterprise\n\n`SCMKit.exe -s gitlab -m addadmin -c userName:password -u https://gitlab.something.local -o targetUserName`\n\n`SCMKit.exe -s gitlab -m addadmin -c apikey -u https://gitlab.something.local -o targetUserName`\n\n##### Bitbucket Server\n\nOnly username/password auth is supported to perform actions not related to repos or projects in Bitbucket.\n\n`SCMKit.exe -s bitbucket -m addadmin -c userName:password -u https://bitbucket.something.local -o targetUserName`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m addadmin -c apikey -u https://gitlab.hogwarts.local -o hgranger\n\n==================================================\nModule:         addadmin\nSystem:         gitlab\nAuth Type:      API Key\nOptions:        hgranger\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      1/14/2022 9:19:32 PM\n==================================================\n\n\n[+] SUCCESS: The hgranger user was successfully added to the admin role.\n\n```\n\n### Remove Admin\n\n#### Use Case\n\n> *Demote an administrative user to a normal user role in a particular SCM system*\n\n#### Syntax\n\nProvide the `removeadmin` module, along with any relevant authentication information and URL. Additionally, provide the target user you would like to remove an administrative role from.\n\n##### GitHub Enterprise\n\n`SCMKit.exe -s github -m removeadmin -c userName:password -u https://github.something.local -o targetUserName`\n\n`SCMKit.exe -s github -m removeadmin -c apikey -u https://github.something.local -o targetUserName`\n\n##### GitLab Enterprise\n\n`SCMKit.exe -s gitlab -m removeadmin -c userName:password -u https://gitlab.something.local -o targetUserName`\n\n`SCMKit.exe -s gitlab -m removeadmin -c apikey -u https://gitlab.something.local -o targetUserName`\n\n##### Bitbucket Server\n\nOnly username/password auth is supported to perform actions not related to repos or projects in Bitbucket.\n\n`SCMKit.exe -s bitbucket -m removeadmin -c userName:password -u https://bitbucket.something.local -o targetUserName`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m removeadmin -c username:password -u https://gitlab.hogwarts.local -o hgranger\n\n==================================================\nModule:         removeadmin\nSystem:         gitlab\nAuth Type:      Username/Password\nOptions:        hgranger\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      1/14/2022 9:20:12 PM\n==================================================\n\n\n[+] SUCCESS: The hgranger user was successfully removed from the admin role.\n\n```\n\n### Create Access Token\n\n#### Use Case\n\n> *Create an access token to be used in a particular SCM system*\n\n#### Syntax\n\nProvide the `createpat` module, along with any relevant authentication information and URL. Additionally, provide the target user you would like to create an access token for.\n\n##### GitLab Enterprise\n\nThis can only be performed as an administrator. You will provide the username that you would like to create a PAT for.\n\n`SCMKit.exe -s gitlab -m createpat -c userName:password -u https://gitlab.something.local -o targetUserName`\n\n`SCMKit.exe -s gitlab -m createpat -c apikey -u https://gitlab.something.local -o targetUserName`\n\n##### Bitbucket Server\n\nCreates PAT for the current user authenticating as. In Bitbucket you cannot create a PAT for another user, even as an admin. Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket. Take note of the PAT ID that is shown after being created. You will need this when you need to remove the PAT in the future.\n\n`SCMKit.exe -s bitbucket -m createpat -c userName:password -u https://bitbucket.something.local `\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m createpat -c username:password -u https://gitlab.hogwarts.local -o hgranger\n\n==================================================\nModule:         createpat\nSystem:         gitlab\nAuth Type:      Username/Password\nOptions:        hgranger\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      1/20/2022 1:51:23 PM\n==================================================\n\n   ID |         Name |                          Token\n-----------------------------------------------------\n   59 | SCMKIT-AaCND |           R3ySx_8HUn6UQ_6onETx\n\n[+] SUCCESS: The hgranger user personal access token was successfully added.\n\n\n```\n\n### List Access Tokens\n\n#### Use Case\n\n> *List access tokens for a user on a particular SCM system*\n\n#### Syntax\n\nProvide the `listpat` module, along with any relevant authentication information and URL. \n\n##### GitLab Enterprise\n\nOnly requires admin if you want to list another user's PAT's. A regular user can list their own PAT's.\n\n`SCMKit.exe -s gitlab -m listpat -c userName:password -u https://gitlab.something.local -o targetUser`\n\n`SCMKit.exe -s gitlab -m listpat -c apikey -u https://gitlab.something.local -o targetUser`\n\n##### Bitbucket Server\n\nList access tokens for current user. Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket.\n\n`SCMKit.exe -s bitbucket -m listpat -c userName:password -u https://bitbucket.something.local`\n\nList access tokens for another user (requires admin). Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket.\n\n`SCMKit.exe -s bitbucket -m listpat -c userName:password -u https://bitbucket.something.local -o targetUser`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m listpat -c username:password -u https://gitlab.hogwarts.local -o hgranger\n\n==================================================\nModule:         listpat\nSystem:         gitlab\nAuth Type:      Username/Password\nOptions:        hgranger\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      1/20/2022 1:54:41 PM\n==================================================\n\n   ID |                 Name |    Active? |                                             Scopes\n----------------------------------------------------------------------------------------------\n   59 |         SCMKIT-AaCND |       True |             api, read_repository, write_repository\n    \n```\n\n### Remove Access Token\n\n#### Use Case\n\n> *Remove an access token for a user in a particular SCM system*\n\n#### Syntax\n\nProvide the `removepat` module, along with any relevant authentication information and URL. Additionally, provide the target user PAT ID you would like to remove an access token for.\n\n##### GitLab Enterprise\n\nOnly requires admin if you want to remove another user's PAT. A regular user can remove their own PAT. You have to provide the PAT ID to remove. This ID was shown whenever you created the PAT and also when you listed the PAT.\n\n`SCMKit.exe -s gitlab -m removepat -c userName:password -u https://gitlab.something.local -o patID`\n\n`SCMKit.exe -s gitlab -m removepat -c apikey -u https://gitlab.something.local -o patID`\n\n##### Bitbucket Server\n\nOnly username/password auth is supported to perform actions not related to repos or projects in Bitbucket. You have to provide the PAT ID to remove. This ID was shown whenever you created the PAT.\n\n`SCMKit.exe -s bitbucket -m removepat -c userName:password -u https://bitbucket.something.local -o patID`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m removepat -c apikey -u https://gitlab.hogwarts.local -o 58\n\n==================================================\nModule:         removepat\nSystem:         gitlab\nAuth Type:      API Key\nOptions:        59\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      1/20/2022 1:56:47 PM\n==================================================\n\n\n\n[*] INFO: Revoking personal access token of ID: 59\n\n\n[+] SUCCESS: The personal access token of ID 59 was successfully revoked.\n\n```\n\n\n### Create SSH Key\n\n#### Use Case\n\n> *Create an SSH key to be used in a particular SCM system*\n\n#### Syntax\n\nProvide the `createsshkey` module, along with any relevant authentication information and URL.\n\n##### GitHub Enterprise\n\nCreates SSH key for the current user authenticating as.\n\n`SCMKit.exe -s github -m createsshkey -c userName:password -u https://github.something.local -o \"ssh public key\"`\n\n`SCMKit.exe -s github -m createsshkey -c apiToken -u https://github.something.local -o \"ssh public key\"`\n\n##### GitLab Enterprise\n\nCreates SSH key for the current user authenticating as. Take note of the SSH key ID that is shown after being created. You will need this when you need to remove the SSH key in the future.\n\n`SCMKit.exe -s gitlab -m createsshkey -c userName:password -u https://gitlab.something.local -o \"ssh public key\"`\n\n`SCMKit.exe -s gitlab -m createsshkey -c apiToken -u https://gitlab.something.local -o \"ssh public key\"`\n\n\n##### Bitbucket Server\n\nCreates SSH key for the current user authenticating as. Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket. Take note of the SSH key ID that is shown after being created. You will need this when you need to remove the SSH key in the future.\n\n`SCMKit.exe -s bitbucket -m createsshkey -c userName:password -u https://bitbucket.something.local -o \"ssh public key\"`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s bitbucket -m createsshkey -c username:password -u https://bitbucket.hogwarts.local -o \"ssh-rsa...\"\n\n==================================================\nModule:         createsshkey\nSystem:         bitbucket\nAuth Type:      Username/Password\nOptions:        ssh-rsa ...\nTarget URL:     http://bitbucket.hogwarts.local:7990\n\nTimestamp:      2/7/2022 1:02:31 PM\n==================================================\n\n  SSH Key ID\n------------\n          16\n\n[+] SUCCESS: The hpotter user SSH key was successfully added.\n\n\n```\n\n### List SSH Keys\n\n#### Use Case\n\n> *List SSH keys for a user on a particular SCM system*\n\n#### Syntax\n\nProvide the `listsshkey` module, along with any relevant authentication information and URL. \n\n##### GitHub Enterprise\n\nList SSH keys for current user. This will include SSH key ID's, which is needed when you would want to remove an SSH key.\n\n`SCMKit.exe -s github -m listsshkey -c userName:password -u https://github.something.local`\n\n`SCMKit.exe -s github -m listsshkey -c apiToken -u https://github.something.local`\n\n##### GitLab Enterprise\n\nList SSH keys for current user.\n\n`SCMKit.exe -s gitlab -m listsshkey -c userName:password -u https://gitlab.something.local`\n\n`SCMKit.exe -s gitlab -m listsshkey -c apiToken -u https://gitlab.something.local`\n\n\n##### Bitbucket Server\n\nList SSH keys for current user. Only username/password auth is supported to perform actions not related to repos or projects in Bitbucket.\n\n`SCMKit.exe -s bitbucket -m listsshkey -c userName:password -u https://bitbucket.something.local`\n\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s gitlab -m listsshkey -u http://gitlab.hogwarts.local -c apiToken\n\n==================================================\nModule:         listsshkey\nSystem:         gitlab\nAuth Type:      API Key\nOptions:\nTarget URL:     https://gitlab.hogwarts.local\n\nTimestamp:      2/7/2022 4:09:40 PM\n==================================================\n\n  SSH Key ID |             SSH Key Value |                Title\n---------------------------------------------------------------\n           9 | .....p50edigBAF4lipVZkAM= |         SCMKIT-RLzie\n          10 | .....vGJLPGHiTwIxW9i+xAs= |         SCMKIT-muFGU\n    \n```\n\n### Remove SSH Key\n\n#### Use Case\n\n> *Remove an SSH key for a user in a particular SCM system*\n\n#### Syntax\n\nProvide the `removesshkey` module, along with any relevant authentication information and URL. Additionally, provide the target user SSH key ID to remove.\n\n##### GitHub Enterprise\n\nYou have to provide the SSH key ID to remove. This ID was shown whenever you list SSH keys.\n\n`SCMKit.exe -s github -m removesshkey -c userName:password -u https://github.something.local -o sshKeyID`\n\n`SCMKit.exe -s github -m removesshkey -c apiToken -u https://github.something.local -o sshKeyID`\n\n##### GitLab Enterprise\n\n You have to provide the SSH key ID to remove. This ID was shown whenever you created the SSH key and is also shown when listing SSH keys.\n\n`SCMKit.exe -s gitlab -m removesshkey -c userName:password -u https://gitlab.something.local -o sshKeyID`\n\n`SCMKit.exe -s gitlab -m removesshkey -c apiToken -u https://gitlab.something.local -o sshKeyID`\n\n##### Bitbucket Server\n\nOnly username/password auth is supported to perform actions not related to repos or projects in Bitbucket. You have to provide the SSH key ID to remove. This ID was shown whenever you created the SSH key and is also shown when listing SSH keys.\n\n`SCMKit.exe -s bitbucket -m removesshkey -c userName:password -u https://bitbucket.something.local -o sshKeyID`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s bitbucket -m removesshkey -u http://bitbucket.hogwarts.local:7990 -c username:password -o 16\n\n==================================================\nModule:         removesshkey\nSystem:         bitbucket\nAuth Type:      Username/Password\nOptions:        16\nTarget URL:     http://bitbucket.hogwarts.local:7990\n\nTimestamp:      2/7/2022 1:48:03 PM\n==================================================\n\n\n[+] SUCCESS: The SSH key of ID 16 was successfully revoked.\n\n```\n\n\n### List Admin Stats\n\n#### Use Case\n\n> *List admin stats in GitHub Enterprise*\n\n#### Syntax\n\nProvide the `adminstats` module, along with any relevant authentication information and URL. Site admin access in GitHub Enterprise is required to use this module\n\n##### GitHub Enterprise\n\n`SCMKit.exe -s github -m adminstats -c userName:password -u https://github.something.local`\n\n`SCMKit.exe -s github -m adminstats -c apikey -u https://github.something.local`\n\n#### Example Output\n\n```\n\nC:\\>SCMKit.exe -s github -m adminstats -c username:password -u https://github-enterprise.hogwarts.local\n\n==================================================\nModule:         adminstats\nSystem:         github\nAuth Type:      Username/Password\nOptions:\nTarget URL:     https://github-enterprise.hogwarts.local\n\nTimestamp:      1/14/2022 9:45:50 PM\n==================================================\n\n     Admin Users |  Suspended Users |      Total Users\n------------------------------------------------------\n               1 |                0 |                5\n\n\n     Total Repos |      Total Wikis\n-----------------------------------\n               4 |                0\n\n\n      Total Orgs |   Total Team Members |      Total Teams\n----------------------------------------------------------\n               1 |                    0 |                0\n\n\n   Private Gists |     Public Gists\n-----------------------------------\n               0 |                1\n               \n```\n\n### List Branch Protection\n\n#### Use Case\n\n> *List branch protections in GitHub Enterprise*\n\n#### Syntax\n\nProvide the `protection` module, along with any relevant authentication information and URL. Optionally, supply a string in the options parameter to return matching results contained in repo names\n\n##### GitHub Enterprise\n\n`SCMKit.exe -s github -m protection -c userName:password -u https://github.something.local`\n\n`SCMKit.exe -s github -m protection -c apikey -u https://github.something.local`\n\n`SCMKit.exe -s github -m protection -c apikey -u https://github.something.local -o reponame`\n\n#### Example Output\n\n```\nC:\\>.\\SCMKit.exe -u http://github.hogwarts.local -s github -c apiToken -m protection -o public-r\n\n==================================================\nModule:         protection\nSystem:         github\nAuth Type:      API Key\nOptions:        public-r\nTarget URL:     http://github.hogwarts.local\n\nTimestamp:      8/29/2022 2:02:42 PM\n==================================================\n\n                     Repo |                    Branch |                                         Protection\n----------------------------------------------------------------------------------------------------------\n              public-repo |                       dev | Protected: True\n                                                        Status checks must pass before merge:\n                                                          Branch must be up-to-date before merge: True\n                                                        Owner review required before merge: True\n                                                        Approvals required before merge: 2\n                                                        Protections apply to repo admins: True\n              public-repo |                      main | Protected: False\n```\n\n## Detection\n\nBelow are static signatures for the specific usage of this tool in its default state:\n\n* Project GUID - `{266C644A-69B1-426B-A47C-1CF32B211F80}`\n  * See [SCMKit Yara Rule](Detections/SCMKit.yar) in this repo.\n* User Agent String - `SCMKIT-5dc493ada400c79dd318abbe770dac7c`\n  * See [SCMKit Snort Rule](Detections/SCMKit.rules) in this repo.\n* Access Token & SSH Key Names - Access tokens and SSH keys that are created using the tool are prepended with `SCMKIT-` for the name.\n\nFor detection guidance of the techniques used by the tool, see the X-Force Red [blog post](https://securityintelligence.com/posts/abusing-source-code-management-systems).\n\n## References\n* Bitbucket API Documentation \n  * https://developer.atlassian.com/server/bitbucket/reference/rest-api/\n* Octokit Documentation\n  * https://octokitnet.readthedocs.io/en/latest/\n  * https://github.com/octokit/octokit.net\n* GitHub API Documentation\n  * https://docs.github.com/en/rest/overview\n* GitLab API Documentation\n  * https://docs.gitlab.com/ee/api/api_resources.html\n* GitLabApiClient Nuget Package Documentation\n  * https://github.com/nmklotas/GitLabApiClient\n"
  },
  {
    "path": "SCMKit/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<configuration>\r\n    <startup> \r\n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.8\" />\r\n    </startup>\r\n  <runtime>\r\n    <assemblyBinding xmlns=\"urn:schemas-microsoft-com:asm.v1\">\r\n      <dependentAssembly>\r\n        <assemblyIdentity name=\"Newtonsoft.Json\" publicKeyToken=\"30ad4fe6b2a6aeed\" culture=\"neutral\" />\r\n        <bindingRedirect oldVersion=\"0.0.0.0-13.0.0.0\" newVersion=\"13.0.0.0\" />\r\n      </dependentAssembly>\r\n    </assemblyBinding>\r\n  </runtime>\r\n</configuration>"
  },
  {
    "path": "SCMKit/FodyWeavers.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Weavers xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"FodyWeavers.xsd\">\r\n  <Costura />\r\n</Weavers>"
  },
  {
    "path": "SCMKit/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following\n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"SCMKit\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"SCMKit\")]\n[assembly: AssemblyCopyright(\"Copyright © 2022\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible\n// to COM components.  If you need to access a type in this assembly from\n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"266c644a-69b1-426b-a47c-1cf32b211f80\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version\n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers\n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.2\")]\n[assembly: AssemblyFileVersion(\"1.2\")]\n"
  },
  {
    "path": "SCMKit/SCMKit.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace SCMKit\r\n{\r\n    class SCMKit\r\n    {\r\n\r\n        // variables to be used\r\n        private static string module = \"\";\r\n        private static string credential = \"\";\r\n        private static string system = \"\";\r\n        private static string url = \"\";\r\n        private static string option = \"\";\r\n        private static List<string> approvedModules = new List<string> { \"listrepo\", \"repolist\", \"reposearch\", \"codesearch\", \"snippetlist\", \"gistlist\", \"orglist\", \"searchrepo\", \"searchcode\", \"searchfile\", \"listsnippet\", \"listgist\", \"listorg\", \"privs\", \"addadmin\", \"removeadmin\", \"createpat\", \"removepat\", \"listpat\", \"adminstats\", \"listrunner\", \"runnerlist\", \"createsshkey\", \"removesshkey\", \"listsshkey\", \"protection\" };\r\n\r\n\r\n        static async Task Main(string[] args)\r\n        {\r\n\r\n            try\r\n            {\r\n\r\n                Dictionary<string, string> argDict = library.Utils.ParseTheArguments(args); // dictionary to hold arguments\r\n\r\n                // if no arguments given, display help and return\r\n                if ((args.Length > 0 && argDict.Count == 0) || argDict.ContainsKey(\"h\") || argDict.ContainsKey(\"help\"))\r\n                {\r\n                    library.Utils.HelpMe();\r\n                    return;\r\n                }\r\n\r\n                // if url is not set, display message and exit\r\n                if ((!argDict.ContainsKey(\"u\") && !argDict.ContainsKey(\"url\")))\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Must supply a URL. See the README.\");\r\n                    return;\r\n                }\r\n\r\n                // if system is not set, display message and exit\r\n                if ((!argDict.ContainsKey(\"s\") && !argDict.ContainsKey(\"system\")))\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Must supply a system. See the README.\");\r\n                    return;\r\n                }\r\n\r\n                // if both module and credential are not given, display message and exit\r\n                if ((!argDict.ContainsKey(\"m\") && !argDict.ContainsKey(\"module\")) && (!argDict.ContainsKey(\"c\") && !argDict.ContainsKey(\"credential\")))\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Must supply both a module and credential. See the README.\");\r\n                    return;\r\n                }\r\n\r\n                // initialize variables\r\n\r\n                // module\r\n                if (argDict.ContainsKey(\"m\") || argDict.ContainsKey(\"module\"))\r\n                {\r\n                    if (argDict.ContainsKey(\"m\"))\r\n                    {\r\n                        module = argDict[\"m\"];\r\n                    }\r\n                    else\r\n                    {\r\n                        module = argDict[\"module\"];\r\n                    }\r\n                }\r\n\r\n                // options\r\n                if (argDict.ContainsKey(\"o\") || argDict.ContainsKey(\"options\"))\r\n                {\r\n                    if (argDict.ContainsKey(\"o\"))\r\n                    {\r\n                        option = argDict[\"o\"];\r\n                    }\r\n                    else\r\n                    {\r\n                        option = argDict[\"options\"];\r\n                    }\r\n                }\r\n\r\n\r\n                // credential\r\n                if (argDict.ContainsKey(\"c\") || argDict.ContainsKey(\"credential\"))\r\n                {\r\n                    if (argDict.ContainsKey(\"c\"))\r\n                    {\r\n                        credential = argDict[\"c\"];\r\n                    }\r\n                    else\r\n                    {\r\n                        credential = argDict[\"credential\"];\r\n                    }\r\n\r\n                }\r\n\r\n\r\n                // url\r\n                if (argDict.ContainsKey(\"u\") || argDict.ContainsKey(\"url\"))\r\n                {\r\n                    if (argDict.ContainsKey(\"u\"))\r\n                    {\r\n                        url = argDict[\"u\"];\r\n                    }\r\n                    else\r\n                    {\r\n                        url = argDict[\"url\"];\r\n                    }\r\n\r\n                }\r\n\r\n\r\n                // system\r\n                if (argDict.ContainsKey(\"s\") || argDict.ContainsKey(\"system\"))\r\n                {\r\n                    if (argDict.ContainsKey(\"s\"))\r\n                    {\r\n                        system = argDict[\"s\"];\r\n                    }\r\n                    else\r\n                    {\r\n                        system = argDict[\"system\"];\r\n                    }\r\n\r\n                }\r\n\r\n                // determine if invalid module was given\r\n                if (!approvedModules.Contains(module.ToLower()))\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Invalid module given. Please see the README for approved modules.\");\r\n                    return;\r\n                }\r\n\r\n\r\n                // system is github\r\n                if (system.ToLower().Equals(\"github\"))\r\n                {\r\n\r\n                    // get to the appropriate module that user specified\r\n                    switch (module.ToLower())\r\n                    {\r\n                        case \"listrepo\":\r\n                            await modules.github.RepoList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"searchrepo\":\r\n                            await modules.github.RepoSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"searchcode\":\r\n                            await modules.github.CodeSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"searchfile\":\r\n                            await modules.github.FileSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"listgist\":\r\n                            await modules.github.GistList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"listorg\":\r\n                            await modules.github.OrgList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"repolist\":\r\n                            await modules.github.RepoList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"reposearch\":\r\n                            await modules.github.RepoSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"codesearch\":\r\n                            await modules.github.CodeSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"filesearch\":\r\n                            await modules.github.FileSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"gistlist\":\r\n                            await modules.github.GistList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"orglist\":\r\n                            await modules.github.OrgList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"privs\":\r\n                            await modules.github.Privs.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"addadmin\":\r\n                            await modules.github.AddAdmin.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"removeadmin\":\r\n                            await modules.github.RemoveAdmin.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"adminstats\":\r\n                            await modules.github.AdminStats.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"createsshkey\":\r\n                            await modules.github.CreateSSHKey.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"listsshkey\":\r\n                            await modules.github.ListSSHKeys.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"removesshkey\":\r\n                            await modules.github.RemoveSSHKey.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"protection\":\r\n                            await modules.github.BranchProtection.execute(credential, url, option, system);\r\n                            break;\r\n                        default:\r\n                            Console.WriteLine(\"\");\r\n                            Console.WriteLine(\"[-] ERROR: That module is not supported for \" + system + \". Please see README\");\r\n                            Console.WriteLine(\"\");\r\n                            Environment.Exit(1);\r\n                            break;\r\n                    }\r\n\r\n                }\r\n\r\n                // system is gitlab\r\n                else if (system.ToLower().Equals(\"gitlab\"))\r\n                {\r\n                    // get to the appropriate module that user specified\r\n                    switch (module.ToLower())\r\n                    {\r\n                        case \"listrepo\":\r\n                            await modules.gitlab.RepoList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"searchrepo\":\r\n                            await modules.gitlab.RepoSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"searchcode\":\r\n                            await modules.gitlab.CodeSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"searchfile\":\r\n                            await modules.gitlab.FileSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"listsnippet\":\r\n                            await modules.gitlab.SnippetList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"repolist\":\r\n                            await modules.gitlab.RepoList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"reposearch\":\r\n                            await modules.gitlab.RepoSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"codesearch\":\r\n                            await modules.gitlab.CodeSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"filesearch\":\r\n                            await modules.gitlab.FileSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"snippetlist\":\r\n                            await modules.gitlab.SnippetList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"privs\":\r\n                            await modules.gitlab.Privs.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"createpat\":\r\n                            await modules.gitlab.CreatePAT.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"listpat\":\r\n                            await modules.gitlab.ListPAT.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"removepat\":\r\n                            await modules.gitlab.RemovePAT.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"addadmin\":\r\n                            await modules.gitlab.AddAdmin.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"removeadmin\":\r\n                            await modules.gitlab.RemoveAdmin.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"listrunner\":\r\n                            await modules.gitlab.RunnerList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"runnerlist\":\r\n                            await modules.gitlab.RunnerList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"createsshkey\":\r\n                            await modules.gitlab.CreateSSHKey.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"removesshkey\":\r\n                            await modules.gitlab.RemoveSSHKey.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"listsshkey\":\r\n                            await modules.gitlab.ListSSHKeys.execute(credential, url, option, system);\r\n                            break;\r\n                        default:\r\n                            Console.WriteLine(\"\");\r\n                            Console.WriteLine(\"[-] ERROR: That module is not supported for \" + system + \". Please see README\");\r\n                            Console.WriteLine(\"\");\r\n                            Environment.Exit(1);\r\n                            break;\r\n                    }\r\n                }\r\n\r\n                // system is bitbucket\r\n                else if (system.ToLower().Equals(\"bitbucket\"))\r\n                {\r\n                    // get to the appropriate module that user specified\r\n                    switch (module.ToLower())\r\n                    {\r\n                        case \"listrepo\":\r\n                            await modules.bitbucket.RepoList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"searchrepo\":\r\n                            await modules.bitbucket.RepoSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"searchcode\":\r\n                            await modules.bitbucket.CodeSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"searchfile\":\r\n                            await modules.bitbucket.FileSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"repolist\":\r\n                            await modules.bitbucket.RepoList.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"reposearch\":\r\n                            await modules.bitbucket.RepoSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"codesearch\":\r\n                            await modules.bitbucket.CodeSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"filesearch\":\r\n                            await modules.bitbucket.FileSearch.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"createpat\":\r\n                            await modules.bitbucket.CreatePAT.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"listpat\":\r\n                            await modules.bitbucket.ListPAT.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"removepat\":\r\n                            await modules.bitbucket.RemovePAT.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"addadmin\":\r\n                            await modules.bitbucket.AddAdmin.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"removeadmin\":\r\n                            await modules.bitbucket.RemoveAdmin.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"createsshkey\":\r\n                            await modules.bitbucket.CreateSSHKey.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"removesshkey\":\r\n                            await modules.bitbucket.RemoveSSHKey.execute(credential, url, option, system);\r\n                            break;\r\n                        case \"listsshkey\":\r\n                            await modules.bitbucket.ListSSHKeys.execute(credential, url, option, system);\r\n                            break;\r\n                        default:\r\n                            Console.WriteLine(\"\");\r\n                            Console.WriteLine(\"[-] ERROR: That module is not supported for \" + system + \". Please see README\");\r\n                            Console.WriteLine(\"\");\r\n                            break;\r\n                    }\r\n                }\r\n\r\n                // invalid system given\r\n                else\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Invalid system given. Please see the README for approved modules.\");\r\n                    return;\r\n                }\r\n\r\n            } // end try\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR : {0}\", ex.Message);\r\n            }\r\n\r\n\r\n        } // end main\r\n\r\n    } // end class\r\n\r\n} // end namespace"
  },
  {
    "path": "SCMKit/SCMKit.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <Import Project=\"..\\packages\\Costura.Fody.3.3.3\\build\\Costura.Fody.props\" Condition=\"Exists('..\\packages\\Costura.Fody.3.3.3\\build\\Costura.Fody.props')\" />\r\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\r\n  <PropertyGroup>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ProjectGuid>{266C644A-69B1-426B-A47C-1CF32B211F80}</ProjectGuid>\r\n    <OutputType>Exe</OutputType>\r\n    <RootNamespace>SCMKit</RootNamespace>\r\n    <AssemblyName>SCMKit</AssemblyName>\r\n    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>\r\n    <FileAlignment>512</FileAlignment>\r\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\r\n    <Deterministic>true</Deterministic>\r\n    <NuGetPackageImportStamp>\r\n    </NuGetPackageImportStamp>\r\n    <PublishUrl>publish\\</PublishUrl>\r\n    <Install>true</Install>\r\n    <InstallFrom>Disk</InstallFrom>\r\n    <UpdateEnabled>false</UpdateEnabled>\r\n    <UpdateMode>Foreground</UpdateMode>\r\n    <UpdateInterval>7</UpdateInterval>\r\n    <UpdateIntervalUnits>Days</UpdateIntervalUnits>\r\n    <UpdatePeriodically>false</UpdatePeriodically>\r\n    <UpdateRequired>false</UpdateRequired>\r\n    <MapFileExtensions>true</MapFileExtensions>\r\n    <ApplicationRevision>0</ApplicationRevision>\r\n    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>\r\n    <IsWebBootstrapper>false</IsWebBootstrapper>\r\n    <UseApplicationTrust>false</UseApplicationTrust>\r\n    <BootstrapperEnabled>true</BootstrapperEnabled>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\r\n    <PlatformTarget>AnyCPU</PlatformTarget>\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <DebugType>full</DebugType>\r\n    <Optimize>false</Optimize>\r\n    <OutputPath>bin\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\r\n    <PlatformTarget>AnyCPU</PlatformTarget>\r\n    <DebugType>none</DebugType>\r\n    <Optimize>true</Optimize>\r\n    <OutputPath>bin\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"Costura, Version=3.3.3.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Costura.Fody.3.3.3\\lib\\net40\\Costura.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"GitLabApiClient, Version=1.8.0.0, Culture=neutral, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\GitLabApiClient.1.8.0\\lib\\net48\\GitLabApiClient.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Newtonsoft.Json.13.0.1\\lib\\net45\\Newtonsoft.Json.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Octokit, Version=2.0.1.0, Culture=neutral, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Octokit.2.0.1\\lib\\netstandard2.0\\Octokit.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"System\" />\r\n    <Reference Include=\"System.Core\" />\r\n    <Reference Include=\"System.Xml.Linq\" />\r\n    <Reference Include=\"System.Data.DataSetExtensions\" />\r\n    <Reference Include=\"Microsoft.CSharp\" />\r\n    <Reference Include=\"System.Data\" />\r\n    <Reference Include=\"System.Net.Http\" />\r\n    <Reference Include=\"System.Xml\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"library\\BitbucketUtils.cs\" />\r\n    <Compile Include=\"library\\GitHubUtils.cs\" />\r\n    <Compile Include=\"library\\GitLabUtils.cs\" />\r\n    <Compile Include=\"library\\Utils.cs\" />\r\n    <Compile Include=\"library\\WebUtils.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\AddAdmin.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\CodeSearch.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\CreatePAT.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\CreateSSHKey.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\FileSearch.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\ListPAT.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\ListSSHKeys.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\RemoveAdmin.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\RemovePAT.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\RemoveSSHKey.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\RepoList.cs\" />\r\n    <Compile Include=\"modules\\bitbucket\\RepoSearch.cs\" />\r\n    <Compile Include=\"modules\\github\\AddAdmin.cs\" />\r\n    <Compile Include=\"modules\\github\\AdminStats.cs\" />\r\n    <Compile Include=\"modules\\github\\BranchProtection.cs\" />\r\n    <Compile Include=\"modules\\github\\CreateSSHKey.cs\" />\r\n    <Compile Include=\"modules\\github\\FileSearch.cs\" />\r\n    <Compile Include=\"modules\\github\\GistList.cs\" />\r\n    <Compile Include=\"modules\\github\\ListSSHKeys.cs\" />\r\n    <Compile Include=\"modules\\github\\OrgList.cs\" />\r\n    <Compile Include=\"modules\\github\\Privs.cs\" />\r\n    <Compile Include=\"modules\\github\\RemoveAdmin.cs\" />\r\n    <Compile Include=\"modules\\github\\RemoveSSHKey.cs\" />\r\n    <Compile Include=\"modules\\github\\RepoList.cs\" />\r\n    <Compile Include=\"modules\\github\\CodeSearch.cs\" />\r\n    <Compile Include=\"modules\\github\\RepoSearch.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\AddAdmin.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\CodeSearch.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\CreatePAT.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\CreateSSHKey.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\FileSearch.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\ListPAT.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\ListSSHKeys.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\Privs.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\RemoveAdmin.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\RemovePAT.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\RemoveSSHKey.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\RepoList.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\RepoSearch.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\RunnerList.cs\" />\r\n    <Compile Include=\"modules\\gitlab\\SnippetList.cs\" />\r\n    <Compile Include=\"SCMKit.cs\" />\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"App.config\" />\r\n    <None Include=\"packages.config\" />\r\n  </ItemGroup>\r\n  <ItemGroup />\r\n  <ItemGroup>\r\n    <BootstrapperPackage Include=\".NETFramework,Version=v4.8\">\r\n      <Visible>False</Visible>\r\n      <ProductName>Microsoft .NET Framework 4.8 %28x86 and x64%29</ProductName>\r\n      <Install>true</Install>\r\n    </BootstrapperPackage>\r\n    <BootstrapperPackage Include=\"Microsoft.Net.Framework.3.5.SP1\">\r\n      <Visible>False</Visible>\r\n      <ProductName>.NET Framework 3.5 SP1</ProductName>\r\n      <Install>false</Install>\r\n    </BootstrapperPackage>\r\n  </ItemGroup>\r\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\r\n  <Import Project=\"..\\packages\\Fody.4.0.2\\build\\Fody.targets\" Condition=\"Exists('..\\packages\\Fody.4.0.2\\build\\Fody.targets')\" />\r\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\r\n    <PropertyGroup>\r\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>\r\n    </PropertyGroup>\r\n    <Error Condition=\"!Exists('..\\packages\\Fody.4.0.2\\build\\Fody.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\Fody.4.0.2\\build\\Fody.targets'))\" />\r\n    <Error Condition=\"!Exists('..\\packages\\Costura.Fody.3.3.3\\build\\Costura.Fody.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\Costura.Fody.3.3.3\\build\\Costura.Fody.props'))\" />\r\n  </Target>\r\n</Project>"
  },
  {
    "path": "SCMKit/library/BitbucketUtils.cs",
    "content": "﻿using System;\r\nusing System.IO;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing Newtonsoft.Json;\r\n\r\nnamespace SCMKit.library\r\n{\r\n    class BitbucketUtils\r\n    {\r\n\r\n\r\n        /**\r\n        * authenticate to Bitbucket to get SESSION ID if not using API auth\r\n        * \r\n        * */\r\n        public static string GetSessionID(string credentials, string url)\r\n        {\r\n            try\r\n            {\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n\r\n                string sessID = \"\";\r\n                bool authValid = false;\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/j_atl_security_check\");\r\n\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"POST\";\r\n                    webRequest.ContentType = \"application/x-www-form-urlencoded\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n                    webRequest.AllowAutoRedirect = false;\r\n                    string[] theCreds = credentials.Split(':');\r\n\r\n\r\n                    // set body and send request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n\r\n                        string body = \"j_username=\" + theCreds[0] + \"&j_password=\" + theCreds[1] + \"&_atl_remember_me=on&submit=Log+in\";\r\n                        streamWriter.Write(body);\r\n                    }\r\n\r\n                    // get the response and the Bitbucket session ID\r\n                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();\r\n                    var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                    string result = streamReader.ReadToEnd();\r\n\r\n                    for (int i = 0; i < httpResponse.Headers.Count; ++i)\r\n                    {\r\n\r\n                        string[] splitValues = httpResponse.Headers[i].Split(',');\r\n                        foreach (string val in splitValues)\r\n                        {\r\n\r\n                            // this header is set only if auth request is valid\r\n                            if (val.Contains(\"_atl_bitbucket_remember_me\"))\r\n                            {\r\n                                authValid = true;\r\n                            }\r\n\r\n                            // get the bitbucket session ID\r\n                            if (val.Contains(\"BITBUCKETSESSIONID=\") && authValid)\r\n                            {\r\n\r\n                                string[] splitValsAgain = val.Split(';');\r\n                                sessID = splitValsAgain[0];\r\n                                sessID = sessID.Replace(\"BITBUCKETSESSIONID=\", \"\");\r\n\r\n                            }\r\n                        }\r\n\r\n\r\n                    }\r\n\r\n                }\r\n\r\n                // if auth was valid return the session ID\r\n                if (authValid)\r\n                {\r\n                    return sessID;\r\n\r\n                }\r\n\r\n                // if auth wasn't valid, return error and exit\r\n                else\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Could not authenticate to URL with credentials provided.\");\r\n                    Console.WriteLine(\"\");\r\n                    return null;\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not authenticate to URL with credentials provided. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n                return null;\r\n            }\r\n\r\n        }\r\n\r\n\r\n\r\n        /**\r\n         * Get the full Bitbucket URL, based on project key and repo slug\r\n         * \r\n         * */\r\n        public static async Task<string> GetFullBitbucketRepoURLAsync(string credential, string sessID, string projKey, string repoSlug, string url)\r\n        {\r\n            string urlToReturn = \"Unable to Determine\";\r\n\r\n            try\r\n            {\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n\r\n                // web request to get a repo details in Bitbucket via API\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/api/1.0/projects/\" + projKey + \"/repos/\" + repoSlug + \"\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    // parse the JSON output and display results\r\n                    JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));\r\n\r\n                    string propName = \"\";\r\n\r\n                    // read the json results\r\n                    while (jsonResult.Read())\r\n                    {\r\n\r\n                        switch (jsonResult.TokenType.ToString())\r\n                        {\r\n                            case \"PropertyName\":\r\n                                propName = jsonResult.Value.ToString();\r\n                                break;\r\n                            case \"String\":\r\n\r\n                                if (propName.ToLower().Equals(\"href\") && jsonResult.Value.ToString().ToLower().Contains(repoSlug) && jsonResult.Value.ToString().EndsWith(\".git\") && jsonResult.Value.ToString().StartsWith(\"http\"))\r\n                                {\r\n                                    urlToReturn = jsonResult.Value.ToString();\r\n                                    urlToReturn = urlToReturn.Replace(\".git\", \"\");\r\n                                }\r\n\r\n                                break;\r\n                            default:\r\n                                break;\r\n\r\n                        }\r\n\r\n                    }\r\n\r\n                }\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                return urlToReturn;\r\n            }\r\n\r\n            return urlToReturn;\r\n\r\n\r\n        }\r\n\r\n\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "SCMKit/library/GitHubUtils.cs",
    "content": "﻿using System;\r\nusing System.IO;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.library\r\n{\r\n    class GitHubUtils\r\n    {\r\n\r\n       /**\r\n       * authenticate to GitHub\r\n       * \r\n       * */\r\n        public static dynamic AuthToGitHub(string credentials, string url)\r\n        {\r\n            try\r\n            {\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n\r\n                GitHubClient client = null;\r\n                Credentials auth = null;\r\n                Uri uri = new Uri(url);\r\n\r\n                client = new GitHubClient(new ProductHeaderValue(\"SCMKIT-5dc493ada400c79dd318abbe770dac7c\"), uri);\r\n\r\n                // if username/password auth being used\r\n                if (credentials.Contains(\":\"))\r\n                {\r\n                    string[] theCreds = credentials.Split(':');\r\n                    auth = new Credentials(theCreds[0], theCreds[1]);\r\n                }\r\n\r\n                // if token auth being used\r\n                else\r\n                {\r\n                    auth = new Credentials(credentials);\r\n                }\r\n\r\n                client.Credentials = auth;\r\n\r\n                return client;\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not authenticate to URL with credentials provided. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n                Environment.Exit(1);\r\n                return null;\r\n            }\r\n\r\n        }\r\n\r\n        public static async Task<string> callGitHubApiGet(string credential, string baseUrl, string path, string query)\r\n        {\r\n            string content = \"\";\r\n            var webRequest = (HttpWebRequest)WebRequest.Create(baseUrl + path + query);\r\n            // set header values\r\n            webRequest.Method = \"GET\";\r\n            webRequest.ContentType = \"application/json\";\r\n            webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n            // if we need to pass the username/password\r\n            if (credential.Contains(\":\"))\r\n            {\r\n                var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(credential));\r\n                webRequest.Headers.Add(\"Authorization\", \"Basic \" + base64EncodedAuthenticationString);\r\n            }\r\n            // if user just specified personal access token\r\n            else\r\n            {\r\n                webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n            }\r\n\r\n            // get web response\r\n            WebResponse response = await webRequest.GetResponseAsync();\r\n            var reader = new StreamReader(response.GetResponseStream());\r\n            content = reader.ReadToEnd();\r\n            return content;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/library/GitLabUtils.cs",
    "content": "﻿using System;\r\nusing System.IO;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing GitLabApiClient;\r\n\r\nnamespace SCMKit.library\r\n{\r\n    class GitLabUtils\r\n    {\r\n\r\n\r\n       /**\r\n       * Get the GitLab project visibilty based on project ID\r\n       * \r\n       * */\r\n        public static async Task<string> GetGitLabProjectVisibility(string credential, string accessToken, string projID, string url)\r\n        {\r\n            string visibility = \"public\";\r\n\r\n            try\r\n            {\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n\r\n                // web request to get details of a project\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/projects/\" + projID);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    // parse response to get visibility\r\n                    int startingIndex = content.IndexOf(\"\\\"visibility\\\":\");\r\n                    int endingIndex = content.IndexOf(\"\\\"owner\\\":{\");\r\n                    visibility = content.Substring(startingIndex + \"\\\"visibility\\\":\".Length, endingIndex - startingIndex - \"\\\"visibility\\\":\".Length);\r\n                    visibility = visibility.Replace(\"\\\"\", \"\");\r\n                    visibility = visibility.Replace(\",\", \"\");\r\n\r\n\r\n                }\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                return visibility;\r\n            }\r\n\r\n            return visibility;\r\n\r\n\r\n        }\r\n\r\n\r\n       /**\r\n       * Authenticate to GitLab\r\n       * \r\n       * */\r\n        public static async Task<GitLabClient> AuthToGitLabAsync(string credentials, string url)\r\n        {\r\n            try\r\n            {\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n\r\n                GitLabClient client = null;\r\n                Uri uri = new Uri(url);\r\n\r\n                // if username/password auth being used\r\n                if (credentials.Contains(\":\"))\r\n                {\r\n                    string[] theCreds = credentials.Split(':');\r\n                    client = new GitLabClient(uri.ToString());\r\n                    await client.LoginAsync(theCreds[0], theCreds[1]);\r\n                }\r\n\r\n                // if token auth being used\r\n                else\r\n                {\r\n                    client = new GitLabClient(uri.ToString(), credentials);\r\n                }\r\n\r\n\r\n                return client;\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not authenticate to URL with credentials provided. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n                return null;\r\n            }\r\n\r\n        }\r\n\r\n\r\n\r\n        /**\r\n        * get access token for GitLab based on username/password given\r\n        * \r\n        * */\r\n        public static string GetAccessToken(string credential, string url)\r\n        {\r\n\r\n            string accessToken = \"\";\r\n\r\n            // get personal access tokens for user\r\n            var webRequestOAuthToken = System.Net.WebRequest.Create(url + \"/oauth/token\");\r\n            if (webRequestOAuthToken != null)\r\n            {\r\n                // set header values\r\n                webRequestOAuthToken.Method = \"POST\";\r\n                webRequestOAuthToken.ContentType = \"application/json\";\r\n\r\n\r\n                // set body and sent request\r\n                using (var streamWriter = new StreamWriter(webRequestOAuthToken.GetRequestStream()))\r\n                {\r\n                    string[] theCreds = credential.Split(':');\r\n                    string json = \"{\\\"grant_type\\\":\\\"password\\\",\\\"scope\\\":\\\"api\\\",\\\"username\\\":\\\"\" + theCreds[0] + \"\\\",\\\"password\\\":\\\"\" + theCreds[1] + \"\\\"}\";\r\n\r\n                    streamWriter.Write(json);\r\n                }\r\n\r\n                // get the response and the access token\r\n                var httpResponse = (HttpWebResponse)webRequestOAuthToken.GetResponse();\r\n                var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                string result = streamReader.ReadToEnd();\r\n                int startIndex = result.IndexOf(\"\\\"access_token\\\":\\\"\");\r\n                int endIndex = result.IndexOf(\"\\\",\\\"token_type\\\":\");\r\n                accessToken = result.Substring(startIndex + \"\\\"access_token\\\":\\\"\".Length, endIndex - startIndex - \"\\\", \\\"token_type\\\":\".Length);\r\n\r\n            }\r\n\r\n            return accessToken;\r\n\r\n        }\r\n\r\n\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "SCMKit/library/Utils.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace SCMKit.library\r\n{\r\n    class Utils\r\n    {\r\n\r\n        /**\r\n        * Parse command line arguments\r\n         * \r\n        * */\r\n        public static Dictionary<string, string> ParseTheArguments(string[] args)\r\n        {\r\n            try\r\n            {\r\n                Dictionary<string, string> ret = new Dictionary<string, string>();\r\n                if (args.Length % 2 == 0 && args.Length > 0)\r\n                {\r\n                    for (int i = 0; i < args.Length; i = i + 2)\r\n                    {\r\n                        ret.Add(args[i].Substring(1, args[i].Length - 1).ToLower(), args[i + 1]);\r\n\r\n                    }\r\n                }\r\n                return ret;\r\n            }\r\n            catch (ArgumentException ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] You specified duplicate switches. Check your command again. Exception: \" + ex.ToString());\r\n                return null;\r\n            }\r\n\r\n        } // end\r\n\r\n\r\n\r\n        /**\r\n        * print help\r\n        * \r\n        * */\r\n        public static void HelpMe()\r\n        {\r\n            Console.Write(\"\\nPlease read the README page for proper usage of the tool.\\n\\n\");\r\n\r\n\r\n        } // end print help method\r\n\r\n\r\n\r\n        /**\r\n        * Generate module header\r\n        * \r\n        * */\r\n        public static string GenerateHeader(string module, string credential, string url, string options, string system)\r\n        {\r\n            string output = String.Empty;\r\n            string delim = \"==================================================\";\r\n            string authType = \"\";\r\n\r\n            if (credential.Contains(\":\"))\r\n            {\r\n                authType = \"Username/Password\";\r\n            }\r\n            else\r\n            {\r\n                authType = \"API Key\";\r\n            }\r\n\r\n            output += \"\\n\" + delim + \"\\n\";\r\n            output += \"Module:\\t\\t\" + module + \"\\n\";\r\n            output += \"System:\\t\\t\" + system + \"\\n\";\r\n            output += \"Auth Type:\\t\" + authType + \"\\n\";\r\n            output += \"Options:\\t\" + options + \"\\n\";\r\n            output += \"Target URL:\\t\" + url + \"\\n\\n\";\r\n            output += \"Timestamp:\\t\" + DateTime.Now + \"\\n\";\r\n            output += delim + \"\\n\";\r\n\r\n            return output;\r\n        }\r\n\r\n\r\n        /**\r\n         * Heartbeat request to indicate it is SCMKit being used for modules not using raw HTTP requests\r\n         * \r\n         */\r\n        public static async Task<WebResponse> HeartbeatRequest(string url)\r\n        {\r\n\r\n\r\n\r\n            ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n            ServicePointManager.Expect100Continue = true;\r\n            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n            WebResponse myWebResponse = null;\r\n\r\n            try\r\n            {\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // get web response\r\n                    myWebResponse = await webRequest.GetResponseAsync();\r\n\r\n\r\n                }\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform heartbeat request. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n                Environment.Exit(1);\r\n            }\r\n\r\n            return myWebResponse;\r\n\r\n        }\r\n\r\n\r\n        /**\r\n         * method to get all indexes where a value exists in a string\r\n         * \r\n         * */\r\n        public static int[] AllIndexesOf(string str, string substr, bool ignoreCase = false)\r\n        {\r\n            if (string.IsNullOrWhiteSpace(str) ||\r\n                string.IsNullOrWhiteSpace(substr))\r\n            {\r\n                throw new ArgumentException(\"String or substring is not specified.\");\r\n            }\r\n\r\n            var indexes = new List<int>();\r\n            int index = 0;\r\n\r\n            while ((index = str.IndexOf(substr, index, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) != -1)\r\n            {\r\n                indexes.Add(index++);\r\n            }\r\n\r\n            return indexes.ToArray();\r\n        }\r\n       \r\n\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "SCMKit/library/WebUtils.cs",
    "content": "﻿using System;\r\nusing System.IO;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace SCMKit.library\r\n{\r\n    class WebUtils\r\n    {\r\n\r\n       /**\r\n      * generate web request\r\n      * \r\n      * */\r\n        public static HttpWebRequest GenerateWebRequest(string credential, string url, string method)\r\n        {\r\n            // Have to use HttpWebRequest class in order to set the Accept property.\r\n            // Can't set the Accept header directly - C# throws an error.\r\n            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);\r\n            request.Method = method;\r\n            request.ContentType = \"application/json\";\r\n            request.Accept = \"application/vnd.github.v3+json\";\r\n            request.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n            if (credential.Contains(\":\"))\r\n            {\r\n                request.Headers.Add(\"Authorization\", \"Basic \" +\r\n                                                       Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(credential)));\r\n            }\r\n            else\r\n            {\r\n                request.Headers.Add(\"Authorization\", \"token \" + credential);\r\n            }\r\n\r\n            return request;\r\n        }\r\n\r\n\r\n\r\n        /**\r\n        * generate raw file web request\r\n        * \r\n        * */\r\n        public static HttpWebRequest GenerateRawFileWebRequest(string credential, string url)\r\n        {\r\n            // Have to use HttpWebRequest class in order to set the Accept property.\r\n            // Can't set the Accept header directly - C# throws an error.\r\n            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);\r\n            request.Method = \"GET\";\r\n            request.Accept = \"application/vnd.github.v3.raw+raw\";\r\n            request.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n            if (credential.Contains(\":\"))\r\n            {\r\n                request.Headers.Add(\"Authorization\", \"Basic \" + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(credential)));\r\n            }\r\n            else\r\n            {\r\n                request.Headers.Add(\"Authorization\", \"token \" + credential);\r\n            }\r\n\r\n            return request;\r\n        }\r\n\r\n\r\n        /**\r\n        * get web response string\r\n        * \r\n        * */\r\n        public static async Task<string> GetRequestResponseString(HttpWebRequest request)\r\n        {\r\n            var responseAsync = await request.GetResponseAsync();\r\n            var responseFromServer = \"\";\r\n            using (var dataStream = responseAsync.GetResponseStream())\r\n            {\r\n                // Open the stream using a StreamReader for easy access.\r\n                var reader = new StreamReader(dataStream);\r\n                // Read the content.\r\n                responseFromServer = reader.ReadToEnd();\r\n            }\r\n            // Close the response.\r\n            responseAsync.Close();\r\n\r\n            return responseFromServer;\r\n        }\r\n\r\n\r\n        /**\r\n        * get web response\r\n        * \r\n        * */\r\n        public static async Task<WebResponse> GetRequestResponse(HttpWebRequest request)\r\n        {\r\n            var responseAsync = await request.GetResponseAsync();\r\n            return responseAsync;\r\n        }\r\n\r\n\r\n        /**\r\n        * ignore SSL\r\n        * \r\n        * */\r\n        public static void IgnoreSSL()\r\n        {\r\n            ServicePointManager.ServerCertificateValidationCallback =\r\n                (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => true;\r\n            ServicePointManager.Expect100Continue = true;\r\n            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/AddAdmin.cs",
    "content": "﻿using System;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n    class AddAdmin\r\n    {\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"addadmin\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n                // if API token was provided, display message and return\r\n                else\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: API token authentication is not supported for this module. Please provide username/password with the appropriate permissions.\");\r\n                    Console.WriteLine(\"\");\r\n                    return;\r\n\r\n                }\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                // web request to add admin via rest API\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/api/1.0/admin/permissions/users?name=\" + options + \"&permission=ADMIN\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"PUT\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool addAdminSuccessful = false;\r\n\r\n                    // figure out if request was successful\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            addAdminSuccessful = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (addAdminSuccessful)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[+] SUCCESS: Successfully added \" + options + \" user to the admin role.\");\r\n                        Console.WriteLine(\"\");\r\n\r\n                    }\r\n\r\n                    // if not successful\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not add user to admin group. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/CodeSearch.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing Newtonsoft.Json;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n\r\n\r\n    // custom class to handle URL results\r\n    public class URLResult\r\n    {\r\n\r\n        public URLResult(string link, string matchingLine, string fileName)\r\n        {\r\n            this.url = link;\r\n            this.matchingLine = matchingLine;\r\n            this.fileName = fileName;\r\n        }\r\n\r\n        public string url { get; set; }\r\n        public string matchingLine { get; set; }\r\n        public string fileName { get; set; }\r\n\r\n    } // end URLResult class\r\n\r\n\r\n    class CodeSearch\r\n    {\r\n\r\n        // dictionary to hold the list of repos and their URLs\r\n        private static List<URLResult> urlResults = new List<URLResult>();\r\n\r\n        private static int matchCount = 0;\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"searchcode\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                // web request to search via rest API\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/search/latest/search\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"POST\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n\r\n                    // set body and send request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n                        string json = \"{\\\"query\\\":\\\"\" + options + \"\\\",\\\"entities\\\":{\\\"code\\\":{}},\\\"limits\\\":{\\\"primary\\\":100,\\\"secondary\\\":100}}\";\r\n                        streamWriter.Write(json);\r\n                    }\r\n\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n\r\n                        // parse the JSON output and display results\r\n                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));\r\n\r\n                        string matchingLine = \"\";\r\n                        string propName = \"\";\r\n                        string projKey = \"\";\r\n                        string repoName = \"\";\r\n                        string fileName = \"\";\r\n                        string nextPageStart = \"\";\r\n                        string isLastPage = \"\";\r\n\r\n                        // read the json results\r\n                        while (jsonResult.Read())\r\n                        {\r\n\r\n                            switch (jsonResult.TokenType.ToString())\r\n                            {\r\n\r\n                                case \"StartObject\":\r\n                                    break;\r\n                                case \"EndObject\":\r\n                                    break;\r\n                                case \"StartArray\":\r\n                                    break;\r\n                                case \"EndArray\":\r\n                                    // add the match to the list\r\n                                    if (!matchingLine.Equals(\"\") && !fileName.Equals(\"\"))\r\n                                    {\r\n                                        bool alreadyExists = false;\r\n                                        string fullURL = await library.BitbucketUtils.GetFullBitbucketRepoURLAsync(credential, sessID, projKey, repoName, url);\r\n\r\n                                        URLResult singleResults = new URLResult(fullURL, matchingLine, fileName);\r\n\r\n                                        // only add if not already found before\r\n                                        foreach (URLResult item in urlResults)\r\n                                        {\r\n                                            if (item.fileName.Equals(fileName) && item.matchingLine.Equals(matchingLine) && item.url.Equals(fullURL))\r\n                                            {\r\n\r\n                                                alreadyExists = true;\r\n                                            }\r\n                                        }\r\n\r\n                                        if (!alreadyExists)\r\n                                        {\r\n                                            urlResults.Add(singleResults);\r\n\r\n                                        }\r\n\r\n                                    }\r\n                                    break;\r\n                                case \"PropertyName\":\r\n                                    propName = jsonResult.Value.ToString();\r\n                                    break;\r\n                                case \"String\":\r\n\r\n                                    // get actual values\r\n                                    if (propName.ToLower().Equals(\"text\"))\r\n                                    {\r\n\r\n                                        string filteredResult = jsonResult.Value.ToString().ToLower();\r\n                                        filteredResult = filteredResult.Replace(\"<em>\", \"\");\r\n                                        filteredResult = filteredResult.Replace(\"</em>\", \"\");\r\n\r\n\r\n                                        if (filteredResult.Contains(options.ToLower()))\r\n                                        {\r\n                                            matchingLine = jsonResult.Value.ToString();\r\n                                        }\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"key\"))\r\n                                    {\r\n                                        projKey = jsonResult.Value.ToString();\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"slug\"))\r\n                                    {\r\n                                        repoName = jsonResult.Value.ToString();\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"file\"))\r\n                                    {\r\n                                        fileName = jsonResult.Value.ToString();\r\n                                    }\r\n                                    break;\r\n                                case \"Integer\":\r\n                                    if (propName.ToLower().Equals(\"nextstart\"))\r\n                                    {\r\n                                        nextPageStart = jsonResult.Value.ToString();\r\n\r\n                                    }\r\n                                    break;\r\n                                case \"Boolean\":\r\n                                    if (propName.ToLower().Equals(\"islastpage\"))\r\n                                    {\r\n                                        isLastPage = jsonResult.Value.ToString();\r\n\r\n                                    }\r\n                                    break;\r\n                                default:\r\n                                    break;\r\n\r\n\r\n                            }\r\n\r\n                        }\r\n\r\n                        // iterate through the dictionary of matching lines and print them\r\n                        foreach (var item in urlResults)\r\n                        {\r\n\r\n                            string theMatch = item.matchingLine;\r\n                            theMatch = theMatch.Replace(\"<em>\", \"\");\r\n                            theMatch = theMatch.Replace(\"</em>\", \"\");\r\n                            theMatch = WebUtility.HtmlDecode(theMatch);\r\n                            Console.WriteLine(\"\\n[>] REPO: \" + item.url);\r\n                            Console.WriteLine(\"    [>] FILE: \" + item.fileName);\r\n                            Console.WriteLine(\"            |_ \" + theMatch);\r\n                            matchCount++;\r\n\r\n                        }\r\n\r\n                        // if there are more pages, then make subsequent requests\r\n                        if (!nextPageStart.Equals(\"\") && isLastPage.Equals(\"False\"))\r\n                        {\r\n                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);\r\n                        }\r\n\r\n\r\n\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"Total matching results: \" + matchCount);\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform code search. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n        // this is just placeholder for making more than 1 request due to paging of results. will have better global solution at some point than this band-aid\r\n        public static async Task makeSubsequentRequestAsync(string credential, string url, string options, string sessID, string nextPage)\r\n        {\r\n\r\n            try\r\n            {\r\n\r\n                urlResults.Clear();\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // web request to search via rest API\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/search/latest/search\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"POST\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n\r\n                    // set body and send request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n                        string json = \"{\\\"query\\\":\\\"\" + options + \"\\\",\\\"entities\\\":{\\\"code\\\":{\\\"start\\\":\" + nextPage + \"}},\\\"limits\\\":{\\\"primary\\\":100,\\\"secondary\\\":100}}\";\r\n                        streamWriter.Write(json);\r\n                    }\r\n\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n\r\n                        // parse the JSON output and display results\r\n                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));\r\n\r\n                        string matchingLine = \"\";\r\n                        string propName = \"\";\r\n                        string projKey = \"\";\r\n                        string repoName = \"\";\r\n                        string fileName = \"\";\r\n                        string nextPageStart = \"\";\r\n                        string isLastPage = \"\";\r\n\r\n                        // read the json results\r\n                        while (jsonResult.Read())\r\n                        {\r\n\r\n                            switch (jsonResult.TokenType.ToString())\r\n                            {\r\n\r\n                                case \"StartObject\":\r\n                                    break;\r\n                                case \"EndObject\":\r\n                                    break;\r\n                                case \"StartArray\":\r\n                                    break;\r\n                                case \"EndArray\":\r\n                                    // add the match to the list\r\n                                    if (!matchingLine.Equals(\"\") && !fileName.Equals(\"\"))\r\n                                    {\r\n                                        bool alreadyExists = false;\r\n                                        string fullURL = await library.BitbucketUtils.GetFullBitbucketRepoURLAsync(credential, sessID, projKey, repoName, url);\r\n\r\n                                        URLResult singleResults = new URLResult(fullURL, matchingLine, fileName);\r\n\r\n                                        // only add if not already found before\r\n                                        foreach (URLResult item in urlResults)\r\n                                        {\r\n                                            if (item.fileName.Equals(fileName) && item.matchingLine.Equals(matchingLine) && item.url.Equals(fullURL))\r\n                                            {\r\n\r\n                                                alreadyExists = true;\r\n                                            }\r\n                                        }\r\n\r\n                                        if (!alreadyExists)\r\n                                        {\r\n                                            urlResults.Add(singleResults);\r\n\r\n                                        }\r\n\r\n                                    }\r\n                                    break;\r\n                                case \"PropertyName\":\r\n                                    propName = jsonResult.Value.ToString();\r\n                                    break;\r\n                                case \"String\":\r\n\r\n                                    // get actual values\r\n                                    if (propName.ToLower().Equals(\"text\"))\r\n                                    {\r\n\r\n                                        string filteredResult = jsonResult.Value.ToString().ToLower();\r\n                                        filteredResult = filteredResult.Replace(\"<em>\", \"\");\r\n                                        filteredResult = filteredResult.Replace(\"</em>\", \"\");\r\n\r\n\r\n                                        if (filteredResult.Contains(options.ToLower()))\r\n                                        {\r\n                                            matchingLine = jsonResult.Value.ToString();\r\n                                        }\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"key\"))\r\n                                    {\r\n                                        projKey = jsonResult.Value.ToString();\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"slug\"))\r\n                                    {\r\n                                        repoName = jsonResult.Value.ToString();\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"file\"))\r\n                                    {\r\n                                        fileName = jsonResult.Value.ToString();\r\n                                    }\r\n                                    break;\r\n                                case \"Integer\":\r\n                                    if (propName.ToLower().Equals(\"nextstart\"))\r\n                                    {\r\n                                        nextPageStart = jsonResult.Value.ToString();\r\n\r\n                                    }\r\n                                    break;\r\n                                case \"Boolean\":\r\n                                    if (propName.ToLower().Equals(\"islastpage\"))\r\n                                    {\r\n                                        isLastPage = jsonResult.Value.ToString();\r\n\r\n                                    }\r\n                                    break;\r\n                                default:\r\n                                    break;\r\n\r\n\r\n                            }\r\n\r\n                        }\r\n\r\n                        // iterate through the dictionary of matching lines and print them\r\n                        foreach (var item in urlResults)\r\n                        {\r\n\r\n                            string theMatch = item.matchingLine;\r\n                            theMatch = theMatch.Replace(\"<em>\", \"\");\r\n                            theMatch = theMatch.Replace(\"</em>\", \"\");\r\n                            theMatch = WebUtility.HtmlDecode(theMatch);\r\n                            Console.WriteLine(\"\\n[>] REPO: \" + item.url);\r\n                            Console.WriteLine(\"    [>] FILE: \" + item.fileName);\r\n                            Console.WriteLine(\"            |_ \" + theMatch);\r\n                            matchCount++;\r\n\r\n                        }\r\n\r\n                        // if there are more pages, then make subsequent requests\r\n                        if (!nextPageStart.Equals(\"\") && isLastPage.Equals(\"False\"))\r\n                        {\r\n                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);\r\n                        }\r\n\r\n\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform code search. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/CreatePAT.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n    class CreatePAT\r\n    {\r\n\r\n        // hashtable to store mapping of PAT and permissions\r\n        private static Dictionary<string, string> patMapping = new Dictionary<string, string>();\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"createpat\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n                // if API token was provided, display message and return\r\n                else\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: API token authentication is not supported for this module. Please provide username/password with the appropriate permissions.\");\r\n                    Console.WriteLine(\"\");\r\n                    return;\r\n\r\n                }\r\n\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,25} | {1,15} | {2,50}\", \"ID\", \"Name\", \"Token\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                string[] splitCred = credential.Split(':');\r\n\r\n                // web request to create PAT via REST api\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/access-tokens/1.0/users/\" + splitCred[0]);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"PUT\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n\r\n                    // set body and send request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n\r\n                        // create random token name\r\n                        Random rd = new Random();\r\n                        const string allowedChars = \"ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\r\n                        char[] chars = new char[5];\r\n\r\n                        for (int i = 0; i < 5; i++)\r\n                        {\r\n                            chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];\r\n                        }\r\n                        string personalAccessTokenName = new string(chars);\r\n                        personalAccessTokenName = \"SCMKIT-\" + personalAccessTokenName;\r\n\r\n\r\n                        string json = \"{\\\"name\\\": \\\"\" + personalAccessTokenName + \"\\\",\\\"permissions\\\": [\\\"REPO_ADMIN\\\",\\\"PROJECT_ADMIN\\\"],\\\"expiryDays\\\": \\\"\\\"}\";\r\n                        streamWriter.Write(json);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n\r\n                        // get the PAT name and id\r\n                        string patName = \"\";\r\n                        int startIndex = content.IndexOf(\"\\\"id\\\":\");\r\n                        int endIndex = content.IndexOf(\"\\\"permissions\\\":\");\r\n                        patName = content.Substring(startIndex + \"\\\"id\\\":\".Length, endIndex - startIndex - \"\\\"id\\\"\".Length);\r\n                        patName = patName.Replace(\"\\\"\", \"\");\r\n                        patName = patName.Replace(\",\", \"\");\r\n                        string[] patNameArray = patName.Split(':');\r\n                        patMapping.Add(patNameArray[0].Replace(\"createdDate\", \"\"), patNameArray[patNameArray.Length - 1]);\r\n\r\n\r\n                        //  parse the actual token\r\n                        string tokenContent = \"\";\r\n                        int startIndexContent = content.IndexOf(\"\\\"token\\\":\");\r\n                        int endIndexContent = content.Length - 1;\r\n                        tokenContent = content.Substring(startIndexContent + \"\\\"token\\\":\".Length, endIndexContent - startIndexContent - \"\\\"token\\\":\".Length);\r\n                        tokenContent = tokenContent.Replace(\"\\\"\", \"\");\r\n\r\n\r\n                        foreach (var item in patMapping)\r\n                        {\r\n                            Console.WriteLine(\"{0,25} | {1,15} | {2,50}\", item.Key, item.Value, tokenContent);\r\n                        }\r\n\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[+] SUCCESS: The \" + splitCred[0] + \" user personal access token was successfully added.\");\r\n                        Console.WriteLine(\"\");\r\n\r\n\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not create PAT. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/CreateSSHKey.cs",
    "content": "﻿using System;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n    class CreateSSHKey\r\n    {\r\n\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"createsshkey\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n                // if API token was provided, display message and return\r\n                else\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: API token authentication is not supported for this module. Please provide username/password with the appropriate permissions.\");\r\n                    Console.WriteLine(\"\");\r\n                    return;\r\n\r\n                }\r\n\r\n\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,12}\", \"SSH Key ID\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                string[] splitCred = credential.Split(':');\r\n\r\n\r\n                // web request to add SSH key via REST API\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/ssh/1.0/keys\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"POST\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n\r\n                    // set body and send request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n\r\n                        // create random SSH Key label\r\n                        Random rd = new Random();\r\n                        const string allowedChars = \"ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\r\n                        char[] chars = new char[5];\r\n\r\n                        for (int i = 0; i < 5; i++)\r\n                        {\r\n                            chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];\r\n                        }\r\n                        string sshKeyLabel = new string(chars);\r\n                        sshKeyLabel = \"SCMKIT-\" + sshKeyLabel;\r\n\r\n                        string json = \"{\\\"\" + \"text\" + \"\\\": \\\"\" + options + \" \" + sshKeyLabel + \"\\\"}\";\r\n                        streamWriter.Write(json);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n\r\n                        // get the SSH key ID\r\n                        string sshKeyID = \"\";\r\n                        int startIndex = content.IndexOf(\"\\\"id\\\":\");\r\n                        int endIndex = content.IndexOf(\"\\\"text\\\":\");\r\n                        sshKeyID = content.Substring(startIndex + \"\\\"id\\\":\".Length, endIndex - startIndex - \"\\\"id\\\"\".Length);\r\n                        sshKeyID = sshKeyID.Replace(\"\\\"\", \"\");\r\n                        sshKeyID = sshKeyID.Replace(\",\", \"\");\r\n\r\n                        Console.WriteLine(\"{0,12}\", sshKeyID);\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[+] SUCCESS: The \" + splitCred[0] + \" user SSH key was successfully added.\");\r\n                        Console.WriteLine(\"\");\r\n\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not create SSH Key. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/FileSearch.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing Newtonsoft.Json;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n    class FileSearch\r\n    {\r\n\r\n        // dictionary to hold the list of repos and their URLs\r\n        private static List<URLResult> urlResults = new List<URLResult>();\r\n\r\n        private static int matchCount = 0;\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"searchfile\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                // web request to search via rest API\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/search/latest/search\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"POST\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n\r\n                    // set body and send request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n                        string json = \"{\\\"query\\\":\\\"\" + options + \"\\\",\\\"entities\\\":{\\\"code\\\":{}},\\\"limits\\\":{\\\"primary\\\":100,\\\"secondary\\\":100}}\";\r\n                        streamWriter.Write(json);\r\n                    }\r\n\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n\r\n                        // parse the JSON output and display results\r\n                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));\r\n\r\n                        string matchingLine = \"\";\r\n                        string propName = \"\";\r\n                        string projKey = \"\";\r\n                        string repoName = \"\";\r\n                        string fileName = \"\";\r\n                        string nextPageStart = \"\";\r\n                        string isLastPage = \"\";\r\n\r\n\r\n                        // read the json results\r\n                        while (jsonResult.Read())\r\n                        {\r\n\r\n                            switch (jsonResult.TokenType.ToString())\r\n                            {\r\n\r\n                                case \"StartObject\":\r\n                                    break;\r\n                                case \"EndObject\":\r\n                                    break;\r\n                                case \"StartArray\":\r\n                                    break;\r\n                                case \"EndArray\":\r\n                                    // add the match to the list\r\n                                    if (!matchingLine.Equals(\"\") && !fileName.Equals(\"\"))\r\n                                    {\r\n                                        bool alreadyExists = false;\r\n                                        string fullURL = await library.BitbucketUtils.GetFullBitbucketRepoURLAsync(credential, sessID, projKey, repoName, url);\r\n\r\n\r\n                                        URLResult singleResults = new URLResult(fullURL, matchingLine, fileName);\r\n\r\n                                        // only add if not already found before\r\n                                        foreach (URLResult item in urlResults)\r\n                                        {\r\n                                            if (item.fileName.Equals(fileName) && item.url.Equals(fullURL))\r\n                                            {\r\n\r\n                                                alreadyExists = true;\r\n                                            }\r\n                                        }\r\n\r\n                                        if (!alreadyExists)\r\n                                        {\r\n                                            urlResults.Add(singleResults);\r\n\r\n                                        }\r\n\r\n                                    }\r\n                                    break;\r\n                                case \"PropertyName\":\r\n                                    propName = jsonResult.Value.ToString();\r\n                                    break;\r\n                                case \"String\":\r\n\r\n                                    // get the actual values\r\n                                    if (propName.ToLower().Equals(\"text\"))\r\n                                    {\r\n                                        if (jsonResult.Value.ToString().ToLower().Contains(options.ToLower()))\r\n                                        {\r\n                                            matchingLine = jsonResult.Value.ToString();\r\n                                        }\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"key\"))\r\n                                    {\r\n                                        projKey = jsonResult.Value.ToString();\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"slug\"))\r\n                                    {\r\n                                        repoName = jsonResult.Value.ToString();\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"file\"))\r\n                                    {\r\n                                        fileName = jsonResult.Value.ToString();\r\n                                    }\r\n                                    break;\r\n                                case \"Integer\":\r\n                                    if (propName.ToLower().Equals(\"nextstart\"))\r\n                                    {\r\n                                        nextPageStart = jsonResult.Value.ToString();\r\n\r\n                                    }\r\n                                    break;\r\n                                case \"Boolean\":\r\n                                    if (propName.ToLower().Equals(\"islastpage\"))\r\n                                    {\r\n                                        isLastPage = jsonResult.Value.ToString();\r\n\r\n                                    }\r\n                                    break;\r\n                                default:\r\n                                    break;\r\n\r\n\r\n                            }\r\n\r\n\r\n                        }\r\n\r\n                        // iterate through the dictionary of matching lines and print them\r\n                        foreach (var item in urlResults)\r\n                        {\r\n                            if (item.fileName.ToLower().Contains(options.ToLower()))\r\n                            {\r\n\r\n                                Console.WriteLine(\"\\n[>] REPO: \" + item.url);\r\n                                Console.WriteLine(\"    [>] FILE: \" + item.fileName);\r\n                                matchCount++;\r\n\r\n                            }\r\n\r\n                        }\r\n\r\n                        // if there are more pages, then make subsequent requests\r\n                        if (!nextPageStart.Equals(\"\") && isLastPage.Equals(\"False\"))\r\n                        {\r\n                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);\r\n                        }\r\n\r\n\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"Total matching results: \" + matchCount);\r\n\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform repo search. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n        // this is just placeholder for making more than 1 request due to paging of results. will have better global solution at some point than this band-aid\r\n        public static async Task makeSubsequentRequestAsync(string credential, string url, string options, string sessID, string nextPage)\r\n        {\r\n\r\n\r\n\r\n            try\r\n            {\r\n\r\n\r\n                urlResults.Clear();\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // web request to search files via REST api\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/search/latest/search\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"POST\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n\r\n                    // set body and send request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n                        string json = \"{\\\"query\\\":\\\"\" + options + \"\\\",\\\"entities\\\":{\\\"code\\\":{\\\"start\\\":\" + nextPage + \"}},\\\"limits\\\":{\\\"primary\\\":100,\\\"secondary\\\":100}}\";\r\n                        streamWriter.Write(json);\r\n                    }\r\n\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n\r\n                        // parse the JSON output and display results\r\n                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));\r\n\r\n                        string matchingLine = \"\";\r\n                        string propName = \"\";\r\n                        string projKey = \"\";\r\n                        string repoName = \"\";\r\n                        string fileName = \"\";\r\n                        string nextPageStart = \"\";\r\n                        string isLastPage = \"\";\r\n\r\n\r\n                        // read the json results\r\n                        while (jsonResult.Read())\r\n                        {\r\n\r\n                            switch (jsonResult.TokenType.ToString())\r\n                            {\r\n\r\n                                case \"StartObject\":\r\n                                    break;\r\n                                case \"EndObject\":\r\n                                    break;\r\n                                case \"StartArray\":\r\n                                    break;\r\n                                case \"EndArray\":\r\n                                    // add the match to the list\r\n                                    if (!matchingLine.Equals(\"\") && !fileName.Equals(\"\"))\r\n                                    {\r\n                                        bool alreadyExists = false;\r\n                                        string fullURL = await library.BitbucketUtils.GetFullBitbucketRepoURLAsync(credential, sessID, projKey, repoName, url);\r\n\r\n\r\n\r\n                                        URLResult singleResults = new URLResult(fullURL, matchingLine, fileName);\r\n\r\n                                        // only add if not already found before\r\n                                        foreach (URLResult item in urlResults)\r\n                                        {\r\n                                            if (item.fileName.Equals(fileName) && item.url.Equals(fullURL))\r\n                                            {\r\n\r\n                                                alreadyExists = true;\r\n                                            }\r\n                                        }\r\n\r\n                                        if (!alreadyExists)\r\n                                        {\r\n                                            urlResults.Add(singleResults);\r\n\r\n                                        }\r\n\r\n                                    }\r\n                                    break;\r\n                                case \"PropertyName\":\r\n                                    propName = jsonResult.Value.ToString();\r\n                                    break;\r\n                                case \"String\":\r\n\r\n                                    // get the actual values\r\n                                    if (propName.ToLower().Equals(\"text\"))\r\n                                    {\r\n                                        if (jsonResult.Value.ToString().ToLower().Contains(options.ToLower()))\r\n                                        {\r\n                                            matchingLine = jsonResult.Value.ToString();\r\n                                        }\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"key\"))\r\n                                    {\r\n                                        projKey = jsonResult.Value.ToString();\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"slug\"))\r\n                                    {\r\n                                        repoName = jsonResult.Value.ToString();\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"file\"))\r\n                                    {\r\n                                        fileName = jsonResult.Value.ToString();\r\n                                    }\r\n                                    break;\r\n                                case \"Integer\":\r\n                                    if (propName.ToLower().Equals(\"nextstart\"))\r\n                                    {\r\n                                        nextPageStart = jsonResult.Value.ToString();\r\n\r\n                                    }\r\n                                    break;\r\n                                case \"Boolean\":\r\n                                    if (propName.ToLower().Equals(\"islastpage\"))\r\n                                    {\r\n                                        isLastPage = jsonResult.Value.ToString();\r\n\r\n                                    }\r\n                                    break;\r\n                                default:\r\n                                    break;\r\n\r\n\r\n                            }\r\n\r\n\r\n                        }\r\n\r\n                        // iterate through the dictionary of matching lines and print them\r\n                        foreach (var item in urlResults)\r\n                        {\r\n                            if (item.fileName.ToLower().Contains(options.ToLower()))\r\n                            {\r\n\r\n                                Console.WriteLine(\"\\n[>] REPO: \" + item.url);\r\n                                Console.WriteLine(\"    [>] FILE: \" + item.fileName);\r\n                                matchCount++;\r\n\r\n                            }\r\n\r\n                        }\r\n\r\n                        // if there are more pages, then make subsequent requests\r\n                        if (!nextPageStart.Equals(\"\") && isLastPage.Equals(\"False\"))\r\n                        {\r\n                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);\r\n                        }\r\n\r\n\r\n\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform file search. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/ListPAT.cs",
    "content": "﻿using System;\r\nusing System.Linq;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n    class ListPAT\r\n    {\r\n\r\n        // hashtable to store mapping of PAT and permissions\r\n        private static Dictionary<string, string> patMapping = new Dictionary<string, string>();\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listpat\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,15} | {1,30} | {2,50}\", \"ID\", \"Name\", \"Permissions\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                string[] splitCred = credential.Split(':');\r\n                string theUser = \"\";\r\n                if (options.Equals(\"\"))\r\n                {\r\n                    theUser = splitCred[0];\r\n                }\r\n                else\r\n                {\r\n                    theUser = options;\r\n                }\r\n\r\n                // web request to get pats via REST api\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/access-tokens/1.0/users/\" + theUser);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n                        // get all instances of PAT ID's\r\n                        IEnumerable<int> startingIndexesPATids = library.Utils.AllIndexesOf(content, \"\\\"id\\\":\\\"\");\r\n                        IEnumerable<int> endingIndexesPATids = library.Utils.AllIndexesOf(content, \"\\\"createdDate\\\":\");\r\n\r\n                        List<string> listOfPatIDs = new List<string>();\r\n                        for (int i = 0; i < startingIndexesPATids.Count(); i++)\r\n                        {\r\n\r\n                            string patID = \"\";\r\n                            patID = content.Substring(startingIndexesPATids.ElementAt(i) + \"\\\"id\\\":\\\"\".Length, endingIndexesPATids.ElementAt(i) - startingIndexesPATids.ElementAt(i) - \"\\\"id\\\":\\\"\".Length);\r\n                            patID = patID.Replace(\"\\\"\", \"\");\r\n                            patID = patID.Replace(\",\", \"\");\r\n                            listOfPatIDs.Add(patID);\r\n\r\n                        }\r\n\r\n\r\n\r\n\r\n                        // get all instances of the token name\r\n                        IEnumerable<int> startingIndexesName = library.Utils.AllIndexesOf(content, \"\\\"createdDate\\\":\");\r\n                        IEnumerable<int> endingIndexesName = library.Utils.AllIndexesOf(content, \"\\\"permissions\\\":\");\r\n\r\n                        List<string> listOfPatNames = new List<string>();\r\n\r\n                        for (int i = 0; i < startingIndexesName.Count(); i++)\r\n                        {\r\n\r\n                            string patName = \"\";\r\n                            patName = content.Substring(startingIndexesName.ElementAt(i) + \"\\\"createdDate\\\":\".Length, endingIndexesName.ElementAt(i) - startingIndexesName.ElementAt(i) - \"\\\"createdDate\\\"\".Length);\r\n                            patName = patName.Replace(\"\\\"\", \"\");\r\n                            patName = patName.Replace(\",\", \"\");\r\n                            string[] patNameArray = patName.Split(':');\r\n                            listOfPatNames.Add(patNameArray[patNameArray.Length - 1]);\r\n\r\n                        }\r\n\r\n\r\n                        // get all instances of the token permissions\r\n                        IEnumerable<int> startingIndexesPermissions = library.Utils.AllIndexesOf(content, \"\\\"permissions\\\":\");\r\n                        IEnumerable<int> endingIndexesPermissions = library.Utils.AllIndexesOf(content, \"\\\"user\\\":\");\r\n\r\n                        List<string> listOfPatPermissions = new List<string>();\r\n\r\n\r\n                        for (int i = 0; i < startingIndexesPermissions.Count(); i++)\r\n                        {\r\n\r\n                            string patPermissions = \"\";\r\n                            patPermissions = content.Substring(startingIndexesPermissions.ElementAt(i) + \"\\\"permissions\\\":\".Length, endingIndexesPermissions.ElementAt(i) - startingIndexesPermissions.ElementAt(i) - \"\\\"permissions\\\"\".Length);\r\n                            patPermissions = patPermissions.Replace(\"\\\"],\\\"\", \"\");\r\n                            patPermissions = patPermissions.Replace(\"[\", \"\");\r\n                            patPermissions = patPermissions.Replace(\"]\", \"\");\r\n                            patPermissions = patPermissions.Replace(\"\\\"\", \"\");\r\n                            listOfPatPermissions.Add(patPermissions);\r\n\r\n                        }\r\n\r\n\r\n                        // the pat names and permissions lists with have same counts, each index is associated with the other list, so list the permissions for each token\r\n                        for (int i = 0; i < listOfPatNames.Count(); i++)\r\n                        {\r\n                            Console.WriteLine(\"{0,15} | {1,30} | {2,50}\", listOfPatIDs[i], listOfPatNames[i], listOfPatPermissions[i]);\r\n\r\n\r\n\r\n                        }\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not retrieve listing of PATs. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/ListSSHKeys.cs",
    "content": "﻿using System;\r\nusing System.Linq;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n\r\n\r\n    class ListSSHKeys\r\n    {\r\n\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listsshkey\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,12} | {1,25} | {2,20}\", \"SSH Key ID\", \"SSH Key Value\", \"Label\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                string[] splitCred = credential.Split(':');\r\n\r\n\r\n                // web request to list SSH keys via REST API\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/ssh/1.0/keys\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    // only proceed if valid creds\r\n                    if (validCreds)\r\n                    {\r\n\r\n\r\n\r\n                        // get all instances of the SSH key id\r\n                        IEnumerable<int> startingIndexesID = library.Utils.AllIndexesOf(content, \"\\\"id\\\":\");\r\n                        IEnumerable<int> endingIndexesID = library.Utils.AllIndexesOf(content, \"\\\"text\\\":\");\r\n\r\n                        List<string> listOfIndexIDs = new List<string>();\r\n\r\n                        for (int i = 0; i < startingIndexesID.Count(); i++)\r\n                        {\r\n\r\n                            string sshKeyID = \"\";\r\n                            sshKeyID = content.Substring(startingIndexesID.ElementAt(i) + \"\\\"id\\\":\".Length, endingIndexesID.ElementAt(i) - startingIndexesID.ElementAt(i) - \"\\\"id\\\"\".Length);\r\n                            sshKeyID = sshKeyID.Replace(\"\\\"\", \"\");\r\n                            sshKeyID = sshKeyID.Replace(\",\", \"\");\r\n                            listOfIndexIDs.Add(sshKeyID);\r\n\r\n                        }\r\n\r\n\r\n                        // get all instances of the SSH key value\r\n                        IEnumerable<int> startingIndexesValue = library.Utils.AllIndexesOf(content, \"\\\"text\\\":\");\r\n                        IEnumerable<int> endingIndexesValue = library.Utils.AllIndexesOf(content, \"\\\"label\\\":\");\r\n\r\n                        List<string> listOfIndexValues = new List<string>();\r\n\r\n                        for (int i = 0; i < startingIndexesValue.Count(); i++)\r\n                        {\r\n\r\n                            string sshKeyValue = \"\";\r\n                            sshKeyValue = content.Substring(startingIndexesValue.ElementAt(i) + \"\\\"text\\\":\".Length, endingIndexesValue.ElementAt(i) - startingIndexesValue.ElementAt(i) - \"\\\"text\\\"\".Length);\r\n                            sshKeyValue = sshKeyValue.Replace(\"\\\"\", \"\");\r\n                            sshKeyValue = sshKeyValue.Replace(\",\", \"\");\r\n                            listOfIndexValues.Add(sshKeyValue);\r\n\r\n\r\n                        }\r\n\r\n\r\n                        // iterate through and print the ssh key ID's and contents\r\n                        for (int i = 0; i < listOfIndexIDs.Count(); i++)\r\n                        {\r\n\r\n                            string[] sshKeyArray = listOfIndexValues[i].Split(' ');\r\n                            string justSSHKey = sshKeyArray[1].Substring(sshKeyArray[1].Length - 20, 20);\r\n                            string justSSHLabel = \"\";\r\n                            //the ssh key label is array value [2]\r\n                            if (sshKeyArray.Length == 3)\r\n                            {\r\n                                justSSHLabel = sshKeyArray[2];\r\n                            }\r\n\r\n                            Console.WriteLine(\"{0,12} | {1,20} | {2,20}\", listOfIndexIDs[i], \".....\" + justSSHKey, justSSHLabel);\r\n                        }\r\n\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not create SSH Key. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/RemoveAdmin.cs",
    "content": "﻿using System;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n    class RemoveAdmin\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"removeadmin\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n                // if API token was provided, display message and return\r\n                else\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: API token authentication is not supported for this module. Please provide username/password with the appropriate permissions.\");\r\n                    Console.WriteLine(\"\");\r\n                    return;\r\n\r\n                }\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                // web request to remove admin via rest API\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/api/1.0/admin/permissions/users?name=\" + options + \"&permission=PROJECT_CREATE\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"PUT\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[+] SUCCESS: Successfully removed \" + options + \" user from the admin role.\");\r\n                        Console.WriteLine(\"\");\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not remove user from admin group. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/RemovePAT.cs",
    "content": "﻿using System;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n    class RemovePAT\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"removepat\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n                // if API token was provided, display message and return\r\n                else\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: API token authentication is not supported for this module. Please provide username/password with the appropriate permissions.\");\r\n                    Console.WriteLine(\"\");\r\n                    return;\r\n\r\n                }\r\n\r\n\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                string[] splitCred = credential.Split(':');\r\n\r\n                // if user didn't specify an ID, display message and return\r\n                if (options.Equals(\"\"))\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Must supply ID of PAT to remove.\");\r\n                    Console.WriteLine(\"\");\r\n                    return;\r\n                }\r\n\r\n                // web request to get pats via REST api\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/access-tokens/1.0/users/\" + splitCred[0] + \"/\" + options);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"DELETE\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[+] SUCCESS: The personal access token of ID \" + options + \" was successfully revoked.\");\r\n                        Console.WriteLine(\"\");\r\n\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not remove PAT. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/RemoveSSHKey.cs",
    "content": "﻿using System;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n    class RemoveSSHKey\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"removesshkey\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n                // if API token was provided, display message and return\r\n                else\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: API token authentication is not supported for this module. Please provide username/password with the appropriate permissions.\");\r\n                    Console.WriteLine(\"\");\r\n                    return;\r\n\r\n                }\r\n\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                string[] splitCred = credential.Split(':');\r\n\r\n                // if user didn't specify an ID, display message and return\r\n                if (options.Equals(\"\"))\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Must supply ID of SSH key to remove.\");\r\n                    Console.WriteLine(\"\");\r\n                    return;\r\n                }\r\n\r\n\r\n                // web request to remove SSH key via REST API\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/ssh/1.0/keys/\" + options);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"DELETE\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n\r\n                    // set body and send request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n\r\n\r\n                        string json = \"{\\\"\" + \"text\" + \"\\\": \\\"\" + options + \"\\\"}\";\r\n                        streamWriter.Write(json);\r\n                    }\r\n\r\n                    // get web response\r\n                    HttpWebResponse myWebResponse = (HttpWebResponse)await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    // if we got 204 response, SSH key was removed\r\n                    if (myWebResponse.StatusCode.ToString().ToLower().Equals(\"nocontent\"))\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[+] SUCCESS: The SSH key of ID \" + options + \" was successfully revoked.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: There was an error revoking the SSH key.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not remove SSH Key. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/RepoList.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing Newtonsoft.Json;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n    class RepoList\r\n    {\r\n\r\n        // dictionary to hold the list of repos and their URLs\r\n        private static Dictionary<string, string> repoMapping = new Dictionary<string, string>();\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listrepo\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,30} | {1,50}\", \"Name\", \"URL\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                // web request to get repos via REST api\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/api/1.0/repos?limit=25\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n\r\n                        // parse the JSON output and display results\r\n                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));\r\n\r\n                        string name = \"\";\r\n                        string link = \"\";\r\n                        string propName = \"\";\r\n                        string nextPageStart = \"\";\r\n\r\n                        // read the json results\r\n                        while (jsonResult.Read())\r\n                        {\r\n                            switch (jsonResult.TokenType.ToString())\r\n                            {\r\n                                case \"StartObject\":\r\n                                    break;\r\n                                case \"EndObject\":\r\n                                    break;\r\n                                case \"StartArray\":\r\n                                    break;\r\n                                case \"EndArray\":\r\n\r\n                                    // add repo name and link to dictionary\r\n                                    if (!name.Equals(\"\") && !link.Equals(\"\"))\r\n                                    {\r\n                                        if (!repoMapping.ContainsKey(name.Trim()) && !repoMapping.ContainsValue(link.Trim()))\r\n                                        {\r\n                                            repoMapping.Add(name.Trim(), link);\r\n                                        }\r\n                                    }\r\n\r\n                                    break;\r\n                                case \"PropertyName\":\r\n                                    propName = jsonResult.Value.ToString();\r\n                                    break;\r\n                                case \"String\":\r\n\r\n                                    if (propName.ToLower().Equals(\"slug\"))\r\n                                    {\r\n                                        name = jsonResult.Value.ToString();\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"href\") && jsonResult.Value.ToString().EndsWith(\".git\") && jsonResult.Value.ToString().StartsWith(\"http\"))\r\n                                    {\r\n                                        link = jsonResult.Value.ToString();\r\n                                    }\r\n                                    break;\r\n                                case \"Integer\":\r\n\r\n                                    if (propName.ToLower().Equals(\"nextpagestart\"))\r\n                                    {\r\n                                        nextPageStart = jsonResult.Value.ToString();\r\n                                    }\r\n\r\n                                    break;\r\n                                default:\r\n                                    break;\r\n\r\n                            }\r\n\r\n                        }\r\n\r\n\r\n                        // iterate throught the dictionary of repos and print them\r\n                        foreach (var item in repoMapping)\r\n                        {\r\n                            Console.WriteLine(\"{0,30} | {1,50}\", item.Key, item.Value);\r\n                        }\r\n\r\n\r\n                        // if there are more pages, then make subsequent requests\r\n                        if (!nextPageStart.Equals(\"\"))\r\n                        {\r\n                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);\r\n                        }\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not retrieve listing of repos. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n\r\n\r\n        // this is just placeholder for making more than 1 request due to paging of results. will have better global solution at some point than this band-aid\r\n        public static async Task makeSubsequentRequestAsync(string credential, string url, string options, string sessID, string nextPage)\r\n        {\r\n\r\n\r\n            try\r\n            {\r\n\r\n                repoMapping.Clear();\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // web request to get repos via REST api\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/api/1.0/repos?limit=25&start=\" + nextPage);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n\r\n                        // parse the JSON output and display results\r\n                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));\r\n\r\n                        string name = \"\";\r\n                        string link = \"\";\r\n                        string propName = \"\";\r\n                        string nextPageStart = \"\";\r\n\r\n                        // read the json results\r\n                        while (jsonResult.Read())\r\n                        {\r\n                            switch (jsonResult.TokenType.ToString())\r\n                            {\r\n                                case \"StartObject\":\r\n                                    break;\r\n                                case \"EndObject\":\r\n                                    break;\r\n                                case \"StartArray\":\r\n                                    break;\r\n                                case \"EndArray\":\r\n\r\n                                    // add repo name and link to dictionary\r\n                                    if (!name.Equals(\"\") && !link.Equals(\"\"))\r\n                                    {\r\n                                        if (!repoMapping.ContainsKey(name.Trim()) && !repoMapping.ContainsValue(link.Trim()))\r\n                                        {\r\n                                            repoMapping.Add(name.Trim(), link);\r\n                                        }\r\n                                    }\r\n\r\n                                    break;\r\n                                case \"PropertyName\":\r\n                                    propName = jsonResult.Value.ToString();\r\n                                    break;\r\n                                case \"String\":\r\n\r\n                                    if (propName.ToLower().Equals(\"slug\"))\r\n                                    {\r\n                                        name = jsonResult.Value.ToString();\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"href\") && jsonResult.Value.ToString().EndsWith(\".git\") && jsonResult.Value.ToString().StartsWith(\"http\"))\r\n                                    {\r\n                                        link = jsonResult.Value.ToString();\r\n                                    }\r\n                                    break;\r\n                                case \"Integer\":\r\n\r\n                                    if (propName.ToLower().Equals(\"nextpagestart\"))\r\n                                    {\r\n                                        nextPageStart = jsonResult.Value.ToString();\r\n                                    }\r\n\r\n                                    break;\r\n                                default:\r\n                                    break;\r\n\r\n                            }\r\n\r\n                        }\r\n\r\n\r\n                        // iterate throught the dictionary of repos and print them\r\n                        foreach (var item in repoMapping)\r\n                        {\r\n                            Console.WriteLine(\"{0,30} | {1,50}\", item.Key, item.Value);\r\n                        }\r\n\r\n                        // if there are more pages, then make subsequent requests\r\n                        if (!nextPageStart.Equals(\"\"))\r\n                        {\r\n                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);\r\n                        }\r\n\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not retrieve listing of repos. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/bitbucket/RepoSearch.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing Newtonsoft.Json;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Net.Security;\r\n\r\nnamespace SCMKit.modules.bitbucket\r\n{\r\n    class RepoSearch\r\n    {\r\n\r\n        // dictionary to hold the list of repos and their URLs\r\n        private static Dictionary<string, string> repoMapping = new Dictionary<string, string>();\r\n\r\n        private static int matchCount = 0;\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"searchrepo\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                string sessID = \"\";\r\n\r\n                // if username/password auth is used, get session ID for remainder of requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n                    sessID = library.BitbucketUtils.GetSessionID(credential, url);\r\n                    if (sessID == null)\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                        return;\r\n\r\n                    }\r\n                }\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,30} | {1,50}\", \"Name\", \"URL\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                // web request to search via REST api\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/api/1.0/repos?limit=25&name=\" + options);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n\r\n                        // parse the JSON output and display results\r\n                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));\r\n\r\n                        string name = \"\";\r\n                        string link = \"\";\r\n                        string propName = \"\";\r\n                        string nextPageStart = \"\";\r\n\r\n\r\n                        // read the json results\r\n                        while (jsonResult.Read())\r\n                        {\r\n\r\n                            switch (jsonResult.TokenType.ToString())\r\n                            {\r\n                                case \"StartObject\":\r\n                                    break;\r\n                                case \"EndObject\":\r\n                                    break;\r\n                                case \"StartArray\":\r\n                                    break;\r\n                                case \"EndArray\":\r\n\r\n                                    // add repo name and link to dictionary\r\n                                    if (!name.Equals(\"\") && !link.Equals(\"\"))\r\n                                    {\r\n                                        if (!repoMapping.ContainsKey(name.Trim()))\r\n                                        {\r\n                                            repoMapping.Add(name.Trim(), link);\r\n                                            matchCount++;\r\n                                        }\r\n                                    }\r\n\r\n                                    break;\r\n                                case \"PropertyName\":\r\n                                    propName = jsonResult.Value.ToString();\r\n                                    break;\r\n                                case \"String\":\r\n                                    if (propName.ToLower().Equals(\"name\"))\r\n                                    {\r\n                                        if (jsonResult.Value.ToString().ToLower().Contains(options.ToLower()))\r\n                                        {\r\n                                            name = jsonResult.Value.ToString();\r\n                                        }\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"href\") && jsonResult.Value.ToString().EndsWith(\".git\") && jsonResult.Value.ToString().StartsWith(\"http\"))\r\n                                    {\r\n                                        link = jsonResult.Value.ToString();\r\n                                    }\r\n                                    break;\r\n                                case \"Integer\":\r\n\r\n                                    if (propName.ToLower().Equals(\"nextpagestart\"))\r\n                                    {\r\n                                        nextPageStart = jsonResult.Value.ToString();\r\n                                    }\r\n                                    break;\r\n                                default:\r\n                                    break;\r\n\r\n                            }\r\n\r\n\r\n\r\n                        }\r\n\r\n                        // iterate throught the dictionary of repos and print them\r\n                        foreach (var item in repoMapping)\r\n                        {\r\n                            Console.WriteLine(\"{0,30} | {1,50}\", item.Key, item.Value);\r\n                        }\r\n\r\n                        // if there are more pages, then make subsequent requests\r\n                        if (!nextPageStart.Equals(\"\"))\r\n                        {\r\n                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);\r\n                        }\r\n\r\n\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"Total matching results: \" + matchCount);\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform repo search. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n\r\n        // this is just placeholder for making more than 1 request due to paging of results. will have better global solution at some point than this band-aid\r\n        public static async Task makeSubsequentRequestAsync(string credential, string url, string options, string sessID, string nextPage)\r\n        {\r\n\r\n\r\n            try\r\n            {\r\n\r\n                repoMapping.Clear();\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // web request to get repos via REST api\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/rest/api/1.0/repos?limit=25&start=\" + nextPage + \"&name=\" + options);\r\n                if (webRequest != null)\r\n                {\r\n\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if username/password auth was used, then pass the sessionID\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Cookie\", \"BITBUCKETSESSIONID= \" + sessID);\r\n                    }\r\n                    // if user just specified http access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    bool validCreds = false;\r\n\r\n                    // figure out if creds valid\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-auserid\"))\r\n                        {\r\n                            validCreds = true;\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    if (validCreds)\r\n                    {\r\n\r\n                        // parse the JSON output and display results\r\n                        JsonTextReader jsonResult = new JsonTextReader(new StringReader(content));\r\n\r\n                        string name = \"\";\r\n                        string link = \"\";\r\n                        string propName = \"\";\r\n                        string nextPageStart = \"\";\r\n\r\n\r\n                        // read the json results\r\n                        while (jsonResult.Read())\r\n                        {\r\n\r\n                            switch (jsonResult.TokenType.ToString())\r\n                            {\r\n                                case \"StartObject\":\r\n                                    break;\r\n                                case \"EndObject\":\r\n                                    break;\r\n                                case \"StartArray\":\r\n                                    break;\r\n                                case \"EndArray\":\r\n\r\n                                    // add repo name and link to dictionary\r\n                                    if (!name.Equals(\"\") && !link.Equals(\"\"))\r\n                                    {\r\n                                        if (!repoMapping.ContainsKey(name.Trim()))\r\n                                        {\r\n                                            repoMapping.Add(name.Trim(), link);\r\n                                            matchCount++;\r\n                                        }\r\n                                    }\r\n\r\n                                    break;\r\n                                case \"PropertyName\":\r\n                                    propName = jsonResult.Value.ToString();\r\n                                    break;\r\n                                case \"String\":\r\n                                    if (propName.ToLower().Equals(\"name\"))\r\n                                    {\r\n                                        if (jsonResult.Value.ToString().ToLower().Contains(options.ToLower()))\r\n                                        {\r\n                                            name = jsonResult.Value.ToString();\r\n                                        }\r\n                                    }\r\n                                    if (propName.ToLower().Equals(\"href\") && jsonResult.Value.ToString().EndsWith(\".git\") && jsonResult.Value.ToString().StartsWith(\"http\"))\r\n                                    {\r\n                                        link = jsonResult.Value.ToString();\r\n                                    }\r\n                                    break;\r\n                                case \"Integer\":\r\n\r\n                                    if (propName.ToLower().Equals(\"nextpagestart\"))\r\n                                    {\r\n                                        nextPageStart = jsonResult.Value.ToString();\r\n                                    }\r\n                                    break;\r\n                                default:\r\n                                    break;\r\n\r\n                            }\r\n\r\n\r\n\r\n                        }\r\n\r\n                        // iterate throught the dictionary of repos and print them\r\n                        foreach (var item in repoMapping)\r\n                        {\r\n                            Console.WriteLine(\"{0,30} | {1,50}\", item.Key, item.Value);\r\n                        }\r\n\r\n                        // if there are more pages, then make subsequent requests\r\n                        if (!nextPageStart.Equals(\"\"))\r\n                        {\r\n                            await makeSubsequentRequestAsync(credential, url, options, sessID, nextPageStart);\r\n                        }\r\n                    }\r\n\r\n                    // if creds invalid\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: Credentials (username/password OR API token) provided are not valid.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform repo search. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/AddAdmin.cs",
    "content": "﻿using Octokit;\r\nusing System;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class AddAdmin\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"addadmin\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n                await client.User.Administration.Promote(options);\r\n\r\n                Console.WriteLine(\"[+] SUCCESS: The user \" + options + \" has been added to site admins\");\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not add user provided to site admin role. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/AdminStats.cs",
    "content": "﻿using System;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class AdminStats\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string option, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"adminstats\", credential, url, option, system));\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n                var data = await client.Enterprise.AdminStats.GetStatisticsAll();\r\n\r\n                // create table headers\r\n                string tableHeader = string.Format(\"{0,16} | {1,16} | {2,16}\", \"Admin Users\", \"Suspended Users\", \"Total Users\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                Console.WriteLine(\"{0,16} | {1,16} | {2,16}\", data.Users.AdminUsers, data.Users.SuspendedUsers, data.Users.TotalUsers);\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"\");\r\n                string tableHeader2 = string.Format(\"{0,16} | {1,16}\", \"Total Repos\", \"Total Wikis\");\r\n                Console.WriteLine(tableHeader2);\r\n                Console.WriteLine(new String('-', tableHeader2.Length));\r\n\r\n                Console.WriteLine(\"{0,16} | {1,16}\", data.Repos.TotalRepos, data.Repos.TotalWikis);\r\n\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"\");\r\n                string tableHeader3 = string.Format(\"{0,16} | {1,20} | {2,16}\", \"Total Orgs\", \"Total Team Members\", \"Total Teams\");\r\n                Console.WriteLine(tableHeader3);\r\n                Console.WriteLine(new String('-', tableHeader3.Length));\r\n\r\n                Console.WriteLine(\"{0,16} | {1,20} | {2,16}\", data.Orgs.TotalOrgs, data.Orgs.TotalTeamMembers, data.Orgs.TotalTeams);\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"\");\r\n                string tableHeader4 = string.Format(\"{0,16} | {1,16}\", \"Private Gists\", \"Public Gists\");\r\n                Console.WriteLine(tableHeader4);\r\n                Console.WriteLine(new String('-', tableHeader4.Length));\r\n\r\n                Console.WriteLine(\"{0,16} | {1,16}\", data.Gists.PrivateGists, data.Gists.PublicGists);\r\n\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not retrieve listing of admin stats. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/BranchProtection.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Threading.Tasks;\r\nusing Newtonsoft.Json.Linq;\r\nusing Octokit;\r\nusing SCMKit.library;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class BranchProtection\r\n    {\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"protection\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,-25} | {1,-25} | {2,-50}\", \"Repo\", \"Branch\", \"Protection\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                IRepositoryBranchesClient branchesClient =\r\n                    new RepositoryBranchesClient(new ApiConnection(client.Connection));\r\n\r\n                SearchRepositoriesRequest searchString = new SearchRepositoriesRequest(); // adding search string in initilization\r\n                if (!string.IsNullOrEmpty(options))\r\n                {\r\n                    searchString = new SearchRepositoriesRequest(options); // adding search string in initilization\r\n                }\r\n                searchString.Stars = Range.GreaterThanOrEquals(0); // using this as a hack to be able to get all repos listed\r\n\r\n                var sa = await client.Search.SearchRepo(searchString);\r\n                int totalNumItems = sa.TotalCount;\r\n\r\n\r\n                // if total number of results is past 100, then iterate through all pages\r\n                if (totalNumItems >= 100)\r\n                {\r\n\r\n                    for (int i = 1; i < (totalNumItems / 100) + 2; i++)\r\n                    {\r\n                        searchString.Page = i;\r\n\r\n                        var search = await client.Search.SearchRepo(searchString);\r\n                        IReadOnlyList<Repository> currentSearch = search.Items;\r\n\r\n                        foreach (Repository repo in currentSearch)\r\n                        {\r\n                            var branches = branchesClient.GetAll(repo.Id);\r\n                            foreach (Branch branch in branches.Result)\r\n                            {\r\n                                var bLen = branch.Name.Length;\r\n                                string protectionSettings = $\"- Protected: {branch.Protected.ToString(),-58}\";\r\n                                if (branch.Protected)\r\n                                {\r\n                                    protectionSettings = $\"+ Protected: {branch.Protected.ToString(),-58}\";\r\n                                    BranchProtectionSettings branchProtection = new BranchProtectionSettings();\r\n                                    try\r\n                                    {\r\n                                        branchProtection = await branchesClient.GetBranchProtection(repo.Id, branch.Name);\r\n                                    }\r\n                                    catch (NotFoundException ex)\r\n                                    {\r\n                                        protectionSettings +=\r\n                                            $\"\\n{\" + \",58}Insufficient privileges to list branch protection rules\";\r\n                                    }\r\n                                    if (branchProtection != null)\r\n                                    {\r\n                                        // List branch protection rules in the order they are displayed in the GitHub web console\r\n                                        if (branchProtection.RequiredPullRequestReviews != null)\r\n                                        {\r\n                                            protectionSettings +=\r\n                                                $\"\\n{\" + \",58}Require a pull request before merging: True\";\r\n                                            if (branchProtection.RequiredPullRequestReviews.RequiredApprovingReviewCount !=\r\n                                                0)\r\n                                                protectionSettings +=\r\n                                                    $\"\\n{\" + \",58}  Approvals required before merge: {branchProtection.RequiredPullRequestReviews.RequiredApprovingReviewCount}\";\r\n                                            if (branchProtection.RequiredPullRequestReviews.RequireCodeOwnerReviews)\r\n                                                protectionSettings +=\r\n                                                    $\"\\n{\" + \",58}  Owner review required before merge: {branchProtection.RequiredPullRequestReviews.RequireCodeOwnerReviews}\";\r\n                                            // Add \"Allow specified actors to bypass required pull requests\" setting when added to Octokit (not supported as of 8/30/22, but supported by GitHub API bypass_pull_request_allowances property)\r\n                                            string bypassPullRequestAllowancesResponse =\r\n                                                await GitHubUtils.callGitHubApiGet(credential, repo.Url, $\"/branches/{branch.Name}/protection/required_pull_request_reviews\", \"\");\r\n                                            if (bypassPullRequestAllowancesResponse.Contains(\r\n                                                    \"bypass_pull_request_allowances\"))\r\n                                            {\r\n                                                protectionSettings +=\r\n                                                    $\"\\n{\" + \",58}  Users who may bypass pull requests:\";\r\n                                                JToken bypassPullRequestAllowanceUsers = JObject.Parse(bypassPullRequestAllowancesResponse)[\"bypass_pull_request_allowances\"];\r\n                                                foreach (var child in bypassPullRequestAllowanceUsers.Children().Children().Children())\r\n                                                {\r\n                                                    JToken user = JObject.Parse(child.ToString());\r\n                                                    protectionSettings += $\"\\n{\" + \",58}    {user[\"login\"]}\";\r\n                                                }\r\n                                            }\r\n                                        }\r\n\r\n                                        if (branchProtection.RequiredStatusChecks != null)\r\n                                        {\r\n                                            protectionSettings +=\r\n                                                $\"\\n{\" + \",58}Status checks must pass before merge:\";\r\n                                            if (branchProtection.RequiredStatusChecks.Strict)\r\n                                                protectionSettings +=\r\n                                                    $\"\\n{\" + \",58}  Branch must be up-to-date before merge: {branchProtection.RequiredStatusChecks.Strict}\";\r\n                                            if (branchProtection.RequiredStatusChecks.Contexts != null)\r\n                                            {\r\n                                                // Context is deprecated, replace with Checks when added to Octokit (not supported as of 8/30/22, but supported by GitHub API)\r\n                                                foreach (string statusCheck in branchProtection.RequiredStatusChecks.Contexts)\r\n                                                    protectionSettings +=\r\n                                                        $\"\\n{\" + \",58}\\n  {statusCheck}\";\r\n                                            }\r\n                                        }\r\n\r\n                                        if (branchProtection.RequiredConversationResolution != null)\r\n                                            protectionSettings += $\"\\n{\" + \",58}Require conversation resolution: {branchProtection.RequiredConversationResolution.Enabled}\";\r\n                                        \r\n                                        if (branchProtection.RequiredSignatures != null)\r\n                                            protectionSettings += $\"\\n{\" + \",58}Require signed commits: {branchProtection.RequiredSignatures.Enabled}\";\r\n                                        \r\n                                        if (branchProtection.RequiredLinearHistory != null)\r\n                                            protectionSettings += $\"\\n{\" + \",58}Require linear history: {branchProtection.RequiredLinearHistory.Enabled}\";\r\n                                        \r\n                                        // Add \"Require deployments to succeed before merging\" setting when added to GitHub API and Octokit (not supported as of 8/30/22)\r\n\r\n                                        if (branchProtection.EnforceAdmins != null)\r\n                                        {\r\n                                            if (branchProtection.EnforceAdmins.Enabled)\r\n                                                protectionSettings +=\r\n                                                    $\"\\n{\" + \",58}Protections apply to repo admins: {branchProtection.EnforceAdmins.Enabled}\";\r\n                                        }\r\n                                        \r\n                                        if (branchProtection.Restrictions != null)\r\n                                        {\r\n                                            protectionSettings +=\r\n                                                $\"\\n{\" + \",58}Push restricted to:\";\r\n                                            if (branchProtection.Restrictions.Users.Count > 0)\r\n                                            {\r\n                                                protectionSettings +=\r\n                                                    $\"\\n{\" + \",58}  Users:\";\r\n                                                foreach (var user in branchProtection.Restrictions.Users)\r\n                                                    protectionSettings +=\r\n                                                        $\"\\n{\" + \",58}    {user.Login}\";\r\n                                            }\r\n\r\n                                            if (branchProtection.Restrictions.Teams.Count > 0)\r\n                                            {\r\n                                                protectionSettings +=\r\n                                                    $\"\\n{\" + \",58}  Teams:\";\r\n                                                foreach (var team in branchProtection.Restrictions.Teams)\r\n                                                    protectionSettings +=\r\n                                                        $\"\\n{\" + \",58}    {team.Name}\";\r\n                                            }\r\n                                            // Add Apps when supported by Octokit (not supported as of 8/30/22, but supported by GitHub API)\r\n                                        }\r\n                                        \r\n                                        if (branchProtection.AllowForcePushes != null)\r\n                                            protectionSettings += $\"\\n{\" + \",58}Allow force pushes: {branchProtection.AllowForcePushes.Enabled}\";\r\n                                        \r\n                                        if (branchProtection.AllowDeletions != null)\r\n                                            protectionSettings += $\"\\n{\" + \",58}Allow deletions: {branchProtection.AllowDeletions.Enabled}\";\r\n                                        \r\n                                        if (branchProtection.BlockCreations != null)\r\n                                            protectionSettings += $\"\\n{\" + \",58}Block creations: {branchProtection.BlockCreations.Enabled}\";\r\n                                    }\r\n                                }\r\n\r\n                                Console.WriteLine(\"{0,-25} | {1,-25} | {2,-50}\", repo.Name, branch.Name, protectionSettings);\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n\r\n                // if number of results is less than 100, just display the 1 page\r\n                else\r\n                {\r\n                    var search = await client.Search.SearchRepo(searchString);\r\n                    IReadOnlyList<Repository> currentSearch = search.Items;\r\n\r\n                    foreach (Repository repo in currentSearch)\r\n                    {\r\n                        var rLen = repo.Name.Length;\r\n                        var branches = branchesClient.GetAll(repo.Id);\r\n                        foreach (Branch branch in branches.Result)\r\n                        {\r\n                            var bLen = branch.Name.Length;\r\n                            string protectionSettings = $\"- Protected: {branch.Protected.ToString(),-58}\";\r\n                            if (branch.Protected)\r\n                            {\r\n                                protectionSettings = $\"+ Protected: {branch.Protected.ToString(),-58}\";\r\n                                BranchProtectionSettings branchProtection = new BranchProtectionSettings();\r\n                                try\r\n                                {\r\n                                    branchProtection = await branchesClient.GetBranchProtection(repo.Id, branch.Name);\r\n                                }\r\n                                catch (NotFoundException ex)\r\n                                {\r\n                                    protectionSettings +=\r\n                                        $\"\\n{\" + \",58}Insufficient privileges to list branch protection rules\";\r\n                                }\r\n                                if (branchProtection != null)\r\n                                {\r\n                                    // List branch protection rules in the order they are displayed in the GitHub web console\r\n                                    if (branchProtection.RequiredPullRequestReviews != null)\r\n                                    {\r\n                                        protectionSettings +=\r\n                                            $\"\\n{\" + \",58}Require a pull request before merging: True\";\r\n                                        if (branchProtection.RequiredPullRequestReviews.RequiredApprovingReviewCount !=\r\n                                            0)\r\n                                            protectionSettings +=\r\n                                                $\"\\n{\" + \",58}  Approvals required before merge: {branchProtection.RequiredPullRequestReviews.RequiredApprovingReviewCount}\";\r\n                                        if (branchProtection.RequiredPullRequestReviews.RequireCodeOwnerReviews)\r\n                                            protectionSettings +=\r\n                                                $\"\\n{\" + \",58}  Owner review required before merge: {branchProtection.RequiredPullRequestReviews.RequireCodeOwnerReviews}\";\r\n                                        // Add \"Allow specified actors to bypass required pull requests\" setting when added to Octokit (not supported as of 8/30/22, but supported by GitHub API bypass_pull_request_allowances property)\r\n                                        string bypassPullRequestAllowancesResponse =\r\n                                            await GitHubUtils.callGitHubApiGet(credential, repo.Url, $\"/branches/{branch.Name}/protection/required_pull_request_reviews\", \"\");\r\n                                        if (bypassPullRequestAllowancesResponse.Contains(\r\n                                                \"bypass_pull_request_allowances\"))\r\n                                        {\r\n                                            protectionSettings +=\r\n                                                $\"\\n{\" + \",58}  Users who may bypass pull requests:\";\r\n                                            JToken bypassPullRequestAllowanceUsers = JObject.Parse(bypassPullRequestAllowancesResponse)[\"bypass_pull_request_allowances\"];\r\n                                            foreach (var child in bypassPullRequestAllowanceUsers.Children().Children().Children())\r\n                                            {\r\n                                                JToken user = JObject.Parse(child.ToString());\r\n                                                protectionSettings += $\"\\n{\" + \",58}    {user[\"login\"]}\";\r\n                                            }\r\n                                        }\r\n                                    }\r\n\r\n                                    if (branchProtection.RequiredStatusChecks != null)\r\n                                    {\r\n                                        protectionSettings +=\r\n                                            $\"\\n{\" + \",58}Status checks must pass before merge:\";\r\n                                        if (branchProtection.RequiredStatusChecks.Strict)\r\n                                            protectionSettings +=\r\n                                                $\"\\n{\" + \",58}  Branch must be up-to-date before merge: {branchProtection.RequiredStatusChecks.Strict}\";\r\n                                        if (branchProtection.RequiredStatusChecks.Contexts != null)\r\n                                        {\r\n                                            // Context is deprecated, replace with Checks when added to Octokit (not supported as of 8/30/22, but supported by GitHub API)\r\n                                            foreach (string statusCheck in branchProtection.RequiredStatusChecks.Contexts)\r\n                                                protectionSettings +=\r\n                                                    $\"\\n{\" + \",58}\\n  {statusCheck}\";\r\n                                        }\r\n                                    }\r\n\r\n                                    if (branchProtection.RequiredConversationResolution != null)\r\n                                        protectionSettings += $\"\\n{\" + \",58}Require conversation resolution: {branchProtection.RequiredConversationResolution.Enabled}\";\r\n                                    \r\n                                    if (branchProtection.RequiredSignatures != null)\r\n                                        protectionSettings += $\"\\n{\" + \",58}Require signed commits: {branchProtection.RequiredSignatures.Enabled}\";\r\n                                    \r\n                                    if (branchProtection.RequiredLinearHistory != null)\r\n                                        protectionSettings += $\"\\n{\" + \",58}Require linear history: {branchProtection.RequiredLinearHistory.Enabled}\";\r\n                                    \r\n                                    // Add \"Require deployments to succeed before merging\" setting when added to GitHub API and Octokit (not supported as of 8/30/22)\r\n\r\n                                    if (branchProtection.EnforceAdmins != null)\r\n                                    {\r\n                                        if (branchProtection.EnforceAdmins.Enabled)\r\n                                            protectionSettings +=\r\n                                                $\"\\n{\" + \",58}Protections apply to repo admins: {branchProtection.EnforceAdmins.Enabled}\";\r\n                                    }\r\n                                    \r\n                                    if (branchProtection.Restrictions != null)\r\n                                    {\r\n                                        protectionSettings +=\r\n                                            $\"\\n{\" + \",58}Push restricted to:\";\r\n                                        if (branchProtection.Restrictions.Users.Count > 0)\r\n                                        {\r\n                                            protectionSettings +=\r\n                                                $\"\\n{\" + \",58}  Users:\";\r\n                                            foreach (var user in branchProtection.Restrictions.Users)\r\n                                                protectionSettings +=\r\n                                                    $\"\\n{\" + \",58}    {user.Login}\";\r\n                                        }\r\n\r\n                                        if (branchProtection.Restrictions.Teams.Count > 0)\r\n                                        {\r\n                                            protectionSettings +=\r\n                                                $\"\\n{\" + \",58}  Teams:\";\r\n                                            foreach (var team in branchProtection.Restrictions.Teams)\r\n                                                protectionSettings +=\r\n                                                    $\"\\n{\" + \",58}    {team.Name}\";\r\n                                        }\r\n                                        // Add Apps when supported by Octokit (not supported as of 8/30/22, but supported by GitHub API)\r\n                                    }\r\n                                    \r\n                                    if (branchProtection.AllowForcePushes != null)\r\n                                        protectionSettings += $\"\\n{\" + \",58}Allow force pushes: {branchProtection.AllowForcePushes.Enabled}\";\r\n                                    \r\n                                    if (branchProtection.AllowDeletions != null)\r\n                                        protectionSettings += $\"\\n{\" + \",58}Allow deletions: {branchProtection.AllowDeletions.Enabled}\";\r\n                                    \r\n                                    if (branchProtection.BlockCreations != null)\r\n                                        protectionSettings += $\"\\n{\" + \",58}Block creations: {branchProtection.BlockCreations.Enabled}\";\r\n                                }\r\n                            }\r\n\r\n                            Console.WriteLine(\"{0,-25} | {1,-25} | {2,-50}\", repo.Name, branch.Name, protectionSettings);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/CodeSearch.cs",
    "content": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text.RegularExpressions;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class CodeSearch\r\n    {\r\n\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"searchcode\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n\r\n                SearchCodeRequest s = new SearchCodeRequest(options); // adding search string in initilization\r\n\r\n                var sa = await client.Search.SearchCode(s);\r\n                int totalNumItems = sa.TotalCount;\r\n\r\n\r\n                // if total number of results is past 100, then iterate through all pages\r\n                if (totalNumItems >= 100)\r\n                {\r\n\r\n                    for (int i = 1; i < (totalNumItems / 100) + 2; i++)\r\n                    {\r\n                        SearchCodeRequest searchString = new SearchCodeRequest(options); // adding search string in initilization\r\n                        searchString.Page = i;\r\n\r\n                        var search = await client.Search.SearchCode(searchString);\r\n                        IReadOnlyList<SearchCode> currentSearch = search.Items;\r\n\r\n                        foreach (SearchCode item in currentSearch)\r\n                        {\r\n                            Console.WriteLine(\"\\n[>] URL: \" + item.HtmlUrl.Replace(\" \", \"\"));\r\n                            await getLinesInFile(credential, item.GitUrl, options);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                // if number of results is less than 100, just display the 1 page\r\n                else\r\n                {\r\n                    SearchCodeRequest searchString = new SearchCodeRequest(options); // adding search string in initilization\r\n\r\n                    var search = await client.Search.SearchCode(searchString);\r\n                    IReadOnlyList<SearchCode> currentSearch = search.Items;\r\n\r\n\r\n\r\n                    foreach (SearchCode item in currentSearch)\r\n                    {\r\n                        Console.WriteLine(\"\\n[>] URL: \" + item.HtmlUrl.Replace(\" \", \"\"));\r\n                        await getLinesInFile(credential, item.GitUrl, options);\r\n                    }\r\n                }\r\n\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"Total number of items matching search: \" + totalNumItems);\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not results of search. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n        }\r\n\r\n        public static async Task getLinesInFile(String credential, String url, String sTerm)\r\n        {\r\n            try\r\n            {\r\n                library.WebUtils.IgnoreSSL();\r\n                var webRequest = library.WebUtils.GenerateRawFileWebRequest(credential, url);\r\n                var versionResponse = await library.WebUtils.GetRequestResponseString(webRequest);\r\n\r\n                String sPattern = \"(.+|)\" + sTerm + \"(.+|)\";\r\n                MatchCollection match = Regex.Matches(versionResponse, sPattern, RegexOptions.IgnoreCase);\r\n\r\n                if (match.Count > 0)\r\n                {\r\n                    Console.WriteLine(\"[*] Match count : \" + match.Count);\r\n                    foreach (Match m in match)\r\n                    {\r\n                        Console.WriteLine(\"    |_ \" + m.Value.Trim());\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    Console.WriteLine(\"[+] Regex did not match file content..\");\r\n                }\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not retrieve file(s) for parsing. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/CreatePAT.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    // TODO\r\n    class CreatePAT\r\n    {\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"createpat\", credential, url, options, system));\r\n\r\n\r\n\r\n            try\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: This module is currently not supported for this system.\");\r\n                Console.WriteLine(\"\");\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not create PAT. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n\r\n\r\n            }\r\n\r\n        }\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/CreateSSHKey.cs",
    "content": "﻿using Octokit;\r\nusing System;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class CreateSSHKey\r\n    {\r\n\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"createsshkey\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n\r\n                // create random key name\r\n                Random rd = new Random();\r\n                const string allowedChars = \"ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\r\n                char[] chars = new char[5];\r\n\r\n                for (int i = 0; i < 5; i++)\r\n                {\r\n                    chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];\r\n                }\r\n                string sshKeyName = new string(chars);\r\n                sshKeyName = \"SCMKIT-\" + sshKeyName;\r\n\r\n                await client.User.GitSshKey.Create(new NewPublicKey(sshKeyName, options));\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[+] SUCCESS: The user SSH key was successfully added.\");\r\n                Console.WriteLine(\"\");\r\n\r\n\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not add user SSH key. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/FileSearch.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n\r\n    // TODO \r\n\r\n    class FileSearch\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"searchfile\", credential, url, options, system));\r\n\r\n\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n\r\n                SearchCodeRequest s = new SearchCodeRequest(options); // adding search string in initilization\r\n                s.In = new[] { CodeInQualifier.Path };\r\n\r\n                var sa = await client.Search.SearchCode(s);\r\n                int totalNumItems = sa.TotalCount;\r\n                int matchCount = 0;\r\n\r\n                // if total number of results is past 100, then iterate through all pages\r\n                if (totalNumItems >= 100)\r\n                {\r\n\r\n                    for (int i = 1; i < (totalNumItems / 100) + 2; i++)\r\n                    {\r\n                        SearchCodeRequest searchString = new SearchCodeRequest(options); // adding search string in initilization\r\n                        searchString.In = new[] { CodeInQualifier.Path };\r\n                        searchString.Page = i;\r\n\r\n                        var search = await client.Search.SearchCode(searchString);\r\n                        IReadOnlyList<SearchCode> currentSearch = search.Items;\r\n\r\n                        foreach (SearchCode item in currentSearch)\r\n                        {\r\n                            if (item.Name.ToLower().Contains(options.ToLower()))\r\n                            {\r\n                                Console.WriteLine(\"\\n[>] REPO: \" + item.Repository.HtmlUrl);\r\n                                Console.WriteLine(\"    [>] FILE: \" + item.HtmlUrl.Replace(\" \", \"\"));\r\n                                matchCount++;\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n\r\n                // if number of results is less than 100, just display the 1 page\r\n                else\r\n                {\r\n                    SearchCodeRequest searchString = new SearchCodeRequest(options); // adding search string in initilization\r\n                    searchString.In = new[] { CodeInQualifier.Path };\r\n\r\n\r\n                    var search = await client.Search.SearchCode(searchString);\r\n                    IReadOnlyList<SearchCode> currentSearch = search.Items;\r\n\r\n\r\n\r\n                    foreach (SearchCode item in currentSearch)\r\n                    {\r\n\r\n                        if (item.Name.ToLower().Contains(options.ToLower()))\r\n                        {\r\n                            Console.WriteLine(\"\\n[>] REPO: \" + item.Repository.HtmlUrl);\r\n                            Console.WriteLine(\"    [>] FILE: \" + item.HtmlUrl.Replace(\" \", \"\"));\r\n                            matchCount++;\r\n                        }\r\n                    }\r\n                }\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"Total number of items matching search: \" + matchCount);\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform file search for search term given. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n\r\n\r\n            }\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/GistList.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class GistList\r\n    {\r\n\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listgist\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n\r\n                var currentGists = await client.Gist.GetAll();\r\n                IEnumerator<Gist> currentUserGists = currentGists.GetEnumerator();\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,40} | {1,10} | {2,50}\", \"Description\", \"Visibility\", \"URL\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                while (currentUserGists.MoveNext())\r\n                {\r\n                    string visibility = \"private\";\r\n                    if (currentUserGists.Current.Public)\r\n                    {\r\n                        visibility = \"public\";\r\n                    }\r\n\r\n                    Console.WriteLine(\"{0,40} | {1,10} | {2,50}\", currentUserGists.Current.Description, visibility, currentUserGists.Current.HtmlUrl);\r\n\r\n\r\n                }\r\n\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not retrieve listing of gists. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/ListPAT.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class ListPAT\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listpat\", credential, url, options, system));\r\n\r\n\r\n\r\n            try\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: This module is currently not supported for this system.\");\r\n                Console.WriteLine(\"\");\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not list PAT Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n\r\n\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n\r\n\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/ListSSHKeys.cs",
    "content": "﻿using Octokit;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\n\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class ListSSHKeys\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listsshkey\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n\r\n\r\n\r\n                var currentSSHKeys = await client.User.GitSshKey.GetAllForCurrent();\r\n\r\n                IEnumerator<Octokit.PublicKey> enumeratorCurrentSSHKeys = currentSSHKeys.GetEnumerator();\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,12} | {1,25} | {2,20}\", \"SSH Key ID\", \"SSH Key Value\", \"Title\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                while (enumeratorCurrentSSHKeys.MoveNext())\r\n                {\r\n                    string[] sshKeyArray = enumeratorCurrentSSHKeys.Current.Key.Split(' ');\r\n                    string justSSHKey = sshKeyArray[1].Substring(sshKeyArray[1].Length - 20, 20);\r\n\r\n                    Console.WriteLine(\"{0,12} | {1,25} | {2,20}\", enumeratorCurrentSSHKeys.Current.Id, \".....\" + justSSHKey, enumeratorCurrentSSHKeys.Current.Title);\r\n\r\n\r\n\r\n                }\r\n\r\n\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not list user SSH keys. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/OrgList.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class OrgList\r\n    {\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listorg\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n\r\n                var currentOrgs = await client.Organization.GetAllForCurrent();\r\n\r\n                IEnumerator<Organization> currentUserOrgs = currentOrgs.GetEnumerator();\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,30} | {1,50}\", \"Name\", \"URL\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                while (currentUserOrgs.MoveNext())\r\n                {\r\n\r\n\r\n                    Console.WriteLine(\"{0,30} | {1,50}\", currentUserOrgs.Current.Login, currentUserOrgs.Current.Url);\r\n\r\n\r\n                }\r\n\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not retrieve listing of organizations. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/Privs.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class Privs\r\n    {\r\n\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            Dictionary<string, string> valuePairs = new Dictionary<string, string>();\r\n            valuePairs.Add(\"repo\", \"Grants full access to repositories, including private repositories.\");\r\n            valuePairs.Add(\"repo:status\", \"Grants read/write access to public and private repository commit statuses.\");\r\n            valuePairs.Add(\"repo_deployment\", \"Grants access to deployment statuses for public and private repositories.\");\r\n            valuePairs.Add(\"public_repo\", \"Limits access to public repositories.\");\r\n            valuePairs.Add(\"repo:invite\", \"Grants accept/decline abilities for invitations to collaborate on a repository.\");\r\n            valuePairs.Add(\"security_events\", \"RW access to security events in code scanning and secret scanning APIs.\");\r\n            valuePairs.Add(\"admin:repo_hook\", \"Grants read, write, ping, and delete access to repository hooks in public and private repositories.\");\r\n            valuePairs.Add(\"write:repo_hook\", \"Grants read, write, and ping access to hooks in public or private repositories.\");\r\n            valuePairs.Add(\"read:repo_hook\", \"Grants read and ping access to hooks in public or private repositories.\");\r\n            valuePairs.Add(\"admin:org\", \"Fully manage the organization and its teams, projects, and memberships.\");\r\n            valuePairs.Add(\"write:org\", \"Read and write access to organization membership, organization projects, and team membership.\");\r\n            valuePairs.Add(\"read:org\", \"Read-only access to organization membership, organization projects, and team membership.\");\r\n            valuePairs.Add(\"admin:public_key\", \"Fully manage public keys.\");\r\n            valuePairs.Add(\"write:public_key\", \"Create, list, and view details for public keys.\");\r\n            valuePairs.Add(\"read:public_key\", \"List and view details for public keys.\");\r\n            valuePairs.Add(\"admin:org_hook\", \"\tGrants read, write, ping, and delete access to organization hooks\");\r\n            valuePairs.Add(\"gist\", \"Grants write access to gists.\");\r\n            valuePairs.Add(\"notifications\", \"Read access to user's notifications\");\r\n            valuePairs.Add(\"user\", \"Grants read/write access to profile info only\");\r\n            valuePairs.Add(\"read:user\", \"Grants access to read a user's profile data.\");\r\n            valuePairs.Add(\"user:email\", \"Grants read access to a user's email addresses.\");\r\n            valuePairs.Add(\"user:follow\", \"Grants access to follow or unfollow other users.\");\r\n            valuePairs.Add(\"delete_repo\", \"Grants access to delete adminable repositories.\");\r\n            valuePairs.Add(\"write:discussion\", \"Allows read and write access for team discussions.\");\r\n            valuePairs.Add(\"read:discussion\", \"Allows read access for team discussions.\");\r\n            valuePairs.Add(\"write:packages\", \"Grants access to upload or publish a package in GitHub Packages. \");\r\n            valuePairs.Add(\"read:packages\", \"Grants access to download or install packages from GitHub Packages.\");\r\n            valuePairs.Add(\"delete:packages\", \"Grants access to delete packages from GitHub Packages.\");\r\n            valuePairs.Add(\"admin:gpg_key\", \"Fully manage GPG keys.\");\r\n            valuePairs.Add(\"write:gpg_key\", \"Create, list, and view details for GPG keys.\");\r\n            valuePairs.Add(\"read:gpg_key\", \"List and view details for GPG keys.\");\r\n            valuePairs.Add(\"workflow\", \"Grants the ability to add and update GitHub Actions workflow files.\");\r\n            valuePairs.Add(\"site_admin\", \"Full site administrator access.\");\r\n            valuePairs.Add(\"admin:enterprise\", \"Full control of enterprise. One step below site admin.\");\r\n\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"privs\", credential, url, options, system));\r\n            List<String> listOfPermissions = new List<String>();\r\n\r\n\r\n            // if username/password auth being used\r\n            if (credential.Contains(\":\"))\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Privs module only supports API key authentication to determine privs of the API key given.\");\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n            // if token auth being used\r\n            else\r\n            {\r\n\r\n\r\n\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,20} | {1,70}\", \"Name\", \"Description\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n\r\n                try\r\n                {\r\n                    ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                    ServicePointManager.Expect100Continue = true;\r\n                    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                    await library.Utils.HeartbeatRequest(url);\r\n\r\n                    var webRequest = System.Net.WebRequest.Create(url + \"/api/v3\");\r\n                    if (webRequest != null)\r\n                    {\r\n                        webRequest.Method = \"GET\";\r\n                        webRequest.ContentType = \"application/json\";\r\n                        webRequest.Headers.Add(\"Authorization\", \"Token \" + credential);\r\n                        WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n\r\n\r\n                        // Display each header and it's key , associated with the response object.\r\n                        for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                        {\r\n\r\n                            if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-oauth-scopes\"))\r\n                            {\r\n                                string[] splitValues = myWebResponse.Headers[i].Split(',');\r\n                                foreach (string val in splitValues)\r\n                                {\r\n                                    foreach (var item in valuePairs)\r\n                                    {\r\n\r\n\r\n                                        if (item.Key.Trim().ToLower().Equals(val.Trim().ToLower()))\r\n                                        {\r\n                                            Console.WriteLine(\"{0,20} | {1,70}\", val.Trim(), item.Value);\r\n                                        }\r\n                                    }\r\n\r\n\r\n                                }\r\n                            }\r\n\r\n\r\n                        }\r\n\r\n                        // Release resources of response object.\r\n                        myWebResponse.Close();\r\n                    }\r\n\r\n\r\n                }\r\n\r\n                catch (Exception ex)\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Could not retrieve listing of privileges for current API token. Exception: \" + ex.ToString());\r\n                    Console.WriteLine(\"\");\r\n                }\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/RemoveAdmin.cs",
    "content": "﻿using Octokit;\r\nusing System;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class RemoveAdmin\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"removeadmin\", credential, url, options, system));\r\n\r\n\r\n            try\r\n            {\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n                await client.User.Administration.Demote(options);\r\n\r\n                Console.WriteLine(\"[+] SUCCESS: The user \" + options + \" has been removed from site admins\");\r\n\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not remove user provided from site admin role. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/RemovePAT.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n\r\n    // TODO\r\n    class RemovePAT\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"removepat\", credential, url, options, system));\r\n\r\n\r\n\r\n            try\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: This module is currently not supported for this system.\");\r\n                Console.WriteLine(\"\");\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not remove PAT. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n\r\n\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/RemoveSSHKey.cs",
    "content": "﻿using Octokit;\r\nusing System;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\n\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class RemoveSSHKey\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"removesshkey\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                // if user didn't specify an ID, display message and return\r\n                if (options.Equals(\"\"))\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Must supply ID of SSH key to remove.\");\r\n                    Console.WriteLine(\"\");\r\n                    return;\r\n                }\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n\r\n\r\n                await client.User.GitSshKey.Delete(Int32.Parse(options));\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[+] SUCCESS: The user SSH key was successfully removed.\");\r\n                Console.WriteLine(\"\");\r\n\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not remove user SSH key. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/RepoList.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class RepoList\r\n    {\r\n\r\n\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listrepo\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,40} | {1,10} | {2,50}\", \"Name\", \"Visibility\", \"URL\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                SearchRepositoriesRequest s = new SearchRepositoriesRequest(); // adding search string in initilization\r\n                s.Stars = Range.GreaterThanOrEquals(0); // using this as a hack to be able to get all repos listed\r\n\r\n                var sa = await client.Search.SearchRepo(s);\r\n                int totalNumItems = sa.TotalCount;\r\n\r\n\r\n                // if total number of results is past 100, then iterate through all pages\r\n                if (totalNumItems >= 100)\r\n                {\r\n\r\n                    for (int i = 1; i < (totalNumItems / 100) + 2; i++)\r\n                    {\r\n                        SearchRepositoriesRequest searchString = new SearchRepositoriesRequest(); // adding search string in initilization\r\n                        searchString.Stars = Range.GreaterThanOrEquals(0);\r\n                        searchString.Page = i;\r\n\r\n                        var search = await client.Search.SearchRepo(searchString);\r\n                        IReadOnlyList<Repository> currentSearch = search.Items;\r\n\r\n                        foreach (Repository item in currentSearch)\r\n                        {\r\n                            string name = \"\";\r\n                            string visibility = \"Unknown\";\r\n                            string itemURL = \"\";\r\n\r\n                            if (item.Name != null)\r\n                            {\r\n                                name = item.Name;\r\n                            }\r\n                            if (item.Visibility.HasValue)\r\n                            {\r\n                                visibility = item.Visibility.Value.ToString();\r\n                            }\r\n\r\n                            if (item.HtmlUrl != null)\r\n                            {\r\n                                itemURL = item.HtmlUrl.Replace(\" \", \"\");\r\n                            }\r\n\r\n                            Console.WriteLine(\"{0,40} | {1,10} | {2,50}\", name, visibility, itemURL);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                // if number of results is less than 100, just display the 1 page\r\n                else\r\n                {\r\n                    SearchRepositoriesRequest searchString = new SearchRepositoriesRequest(); // adding search string in initilization\r\n                    searchString.Stars = Range.GreaterThanOrEquals(0);\r\n\r\n                    var search = await client.Search.SearchRepo(searchString);\r\n                    IReadOnlyList<Repository> currentSearch = search.Items;\r\n\r\n\r\n\r\n                    foreach (Repository item in currentSearch)\r\n                    {\r\n                        string name = \"\";\r\n                        string visibility = \"Unknown\";\r\n                        string itemURL = \"\";\r\n\r\n                        if (item.Name != null)\r\n                        {\r\n                            name = item.Name;\r\n                        }\r\n                        if (item.Visibility.HasValue)\r\n                        {\r\n                            visibility = item.Visibility.Value.ToString();\r\n                        }\r\n\r\n                        if (item.HtmlUrl != null)\r\n                        {\r\n                            itemURL = item.HtmlUrl.Replace(\" \", \"\");\r\n                        }\r\n\r\n                        Console.WriteLine(\"{0,40} | {1,10} | {2,50}\", name, visibility, itemURL);\r\n                    }\r\n                }\r\n\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not retrieve listing of repos. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/github/RepoSearch.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing Octokit;\r\n\r\nnamespace SCMKit.modules.github\r\n{\r\n    class RepoSearch\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"searchrepo\", credential, url, options, system));\r\n\r\n\r\n\r\n            try\r\n            {\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                GitHubClient client = library.GitHubUtils.AuthToGitHub(credential, url);\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,40} | {1,10} | {2,50}\", \"Name\", \"Visibility\", \"URL\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n\r\n                SearchRepositoriesRequest s = new SearchRepositoriesRequest(options); // adding search string in initilization\r\n\r\n\r\n                var sa = await client.Search.SearchRepo(s);\r\n                int totalNumItems = sa.TotalCount;\r\n\r\n\r\n                // if total number of results is past 100, then iterate through all pages\r\n                if (totalNumItems >= 100)\r\n                {\r\n\r\n                    for (int i = 1; i < (totalNumItems / 100) + 2; i++)\r\n                    {\r\n                        SearchRepositoriesRequest searchString = new SearchRepositoriesRequest(options); // adding search string in initilization\r\n                        searchString.Page = i;\r\n\r\n                        var search = await client.Search.SearchRepo(searchString);\r\n                        IReadOnlyList<Repository> currentSearch = search.Items;\r\n\r\n                        foreach (Repository item in currentSearch)\r\n                        {\r\n\r\n                            string name = \"\";\r\n                            string visibility = \"Not Found\";\r\n                            string itemURL = \"\";\r\n\r\n                            if (item.Name != null)\r\n                            {\r\n                                name = item.Name;\r\n                            }\r\n                            if (item.Visibility.HasValue)\r\n                            {\r\n                                visibility = item.Visibility.Value.ToString();\r\n                            }\r\n\r\n                            if (item.HtmlUrl != null)\r\n                            {\r\n                                itemURL = item.HtmlUrl.Replace(\" \", \"\");\r\n                            }\r\n\r\n                            Console.WriteLine(\"{0,40} | {1,10} | {2,50}\", name, visibility, itemURL);\r\n\r\n                        }\r\n                    }\r\n                }\r\n\r\n                // if number of results is less than 100, just display the 1 page\r\n                else\r\n                {\r\n\r\n                    IReadOnlyList<Repository> currentSearch = sa.Items;\r\n\r\n\r\n                    foreach (Repository item in currentSearch)\r\n                    {\r\n\r\n                        string name = \"\";\r\n                        string visibility = \"Unknown\";\r\n                        string itemURL = \"\";\r\n\r\n                        if (item.Name != null)\r\n                        {\r\n                            name = item.Name;\r\n                        }\r\n                        if (item.Visibility.HasValue)\r\n                        {\r\n                            visibility = item.Visibility.Value.ToString();\r\n                        }\r\n\r\n                        if (item.HtmlUrl != null)\r\n                        {\r\n                            itemURL = item.HtmlUrl.Replace(\" \", \"\");\r\n                        }\r\n\r\n                        Console.WriteLine(\"{0,40} | {1,10} | {2,50}\", name, visibility, itemURL);\r\n                    }\r\n                }\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"Total number of items matching search: \" + totalNumItems);\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform repo search for search term given. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n\r\n\r\n            }\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/AddAdmin.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing GitLabApiClient;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n    class AddAdmin\r\n    {\r\n\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"addadmin\", credential, url, options, system));\r\n\r\n            // dictionary to hold lookup table user ID's and usernames\r\n            Dictionary<string, string> userMapping = new Dictionary<string, string>();\r\n\r\n            try\r\n            {\r\n\r\n                // auth to GitLab and get list of all users\r\n                Task<GitLabClient> authTask = library.GitLabUtils.AuthToGitLabAsync(credential, url);\r\n                GitLabClient client = authTask.Result;\r\n                var users = await client.Users.GetAsync();\r\n\r\n                // add associated user and user id to the dictionary for subsequent requests\r\n                foreach (var user in users)\r\n                {\r\n                    userMapping.Add(user.Username, user.Id.ToString());\r\n                }\r\n\r\n\r\n\r\n                // proceed with request to add admin permissions for the user given\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n                string theUserID = userMapping[options.ToLower()];\r\n\r\n                // get snippets for user\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/users/\" + theUserID);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"PUT\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n\r\n                    // set body and sent request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n                        string json = \"{\\\"admin\\\":\\\"true\\\"}\";\r\n                        streamWriter.Write(json);\r\n                    }\r\n\r\n                    // get the response and the access token\r\n                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();\r\n                    var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                    string result = streamReader.ReadToEnd();\r\n\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[+] SUCCESS: The \" + options + \" user was successfully added to the admin role.\");\r\n                    Console.WriteLine(\"\");\r\n\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (KeyNotFoundException ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: User provided does not exist to modify. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not add user to admin role. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/CodeSearch.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing Newtonsoft.Json;\r\nusing GitLabApiClient;\r\n\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n\r\n    // custom class to handle the JSON output of search result\r\n    public class gitlabSearchResult\r\n    {\r\n\r\n        public string basename { get; set; }\r\n        public string data { get; set; }\r\n        public string path { get; set; }\r\n        public string filename { get; set; }\r\n        public string id { get; set; }\r\n        public string reference { get; set; }\r\n        public int startLine { get; set; }\r\n        public int project_id { get; set; }\r\n\r\n        public gitlabSearchResult()\r\n        {\r\n\r\n        }\r\n\r\n    }\r\n\r\n\r\n    class CodeSearch\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"searchcode\", credential, url, options, system));\r\n\r\n            // lists to hold project ID's and mappings\r\n            List<string> listOfProjectIds = new List<string>();\r\n            Dictionary<string, string> projectMapping = new Dictionary<string, string>();\r\n\r\n\r\n            try\r\n            {\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                // auth to GitLab and get list of all projects\r\n                Task<GitLabClient> authTask = library.GitLabUtils.AuthToGitLabAsync(credential, url);\r\n                GitLabClient client = authTask.Result;\r\n                var projects = await client.Projects.GetAsync();\r\n\r\n                foreach (var project in projects)\r\n                {\r\n\r\n                    listOfProjectIds.Add(project.Id.ToString());\r\n                    projectMapping.Add(project.Id.ToString(), project.WebUrl);\r\n\r\n                }\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // proceed with performing the search since we have all the project ID's and mappings\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n\r\n                int searchMatchCount = 0;\r\n\r\n                // perform the search for code with search term against each project using the project search API\r\n                foreach (string projectToSearch in listOfProjectIds)\r\n                {\r\n\r\n                    var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/projects/\" + projectToSearch + \"/search?scope=blobs&search=\" + options);\r\n                    if (webRequest != null)\r\n                    {\r\n                        // set header values\r\n                        webRequest.Method = \"GET\";\r\n                        webRequest.ContentType = \"application/json\";\r\n                        webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                        // if we need to pass the token obtained from the username/password auth\r\n                        if (credential.Contains(\":\"))\r\n                        {\r\n                            webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                        }\r\n                        // if user just specified personal access token\r\n                        else\r\n                        {\r\n                            webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                        }\r\n\r\n                        // get web response\r\n                        WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                        string content;\r\n                        var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                        content = reader.ReadToEnd();\r\n\r\n                        // parse the JSON output and display results\r\n                        List<gitlabSearchResult> searchResults = JsonConvert.DeserializeObject<List<gitlabSearchResult>>(content);\r\n                        foreach (gitlabSearchResult item in searchResults)\r\n                        {\r\n\r\n                            Console.WriteLine(\"\\n[>] URL: \" + projectMapping[projectToSearch] + \"/\" + item.path);\r\n\r\n                            // get the actual line where the match happened\r\n                            string[] lines = item.data.Split(new string[] { \"\\r\\n\", \"\\r\", \"\\n\" }, StringSplitOptions.None);\r\n                            foreach (string line in lines)\r\n                            {\r\n                                if (line.ToLower().Contains(options.ToLower()))\r\n                                {\r\n                                    searchMatchCount++;\r\n                                    Console.WriteLine(\"    |_ \" + line.Trim());\r\n\r\n                                }\r\n                            }\r\n\r\n                        }\r\n\r\n                    }\r\n                }\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"Total number of items matching code search: \" + searchMatchCount);\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform code search for search term given. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/CreatePAT.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing GitLabApiClient;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n    class CreatePAT\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"createpat\", credential, url, options, system));\r\n\r\n            // dictionary to hold lookup table user ID's and usernames\r\n            Dictionary<string, string> userMapping = new Dictionary<string, string>();\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                // auth to GitLab and get list of all users\r\n                Task<GitLabClient> authTask = library.GitLabUtils.AuthToGitLabAsync(credential, url);\r\n                GitLabClient client = authTask.Result;\r\n                var users = await client.Users.GetAsync();\r\n\r\n                // add associated user and user id to the dictionary for subsequent requests\r\n                foreach (var user in users)\r\n                {\r\n                    userMapping.Add(user.Username, user.Id.ToString());\r\n                }\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // proceed with request to create PAT for the user given\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n                string theUserID = userMapping[options.ToLower()];\r\n\r\n                // perform request to create personal access token\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/users/\" + theUserID + \"/personal_access_tokens\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"POST\";\r\n                    webRequest.ContentType = \"application/x-www-form-urlencoded\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n\r\n                    // set body and sent request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n\r\n                        // create random token name\r\n                        Random rd = new Random();\r\n                        const string allowedChars = \"ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\r\n                        char[] chars = new char[5];\r\n\r\n                        for (int i = 0; i < 5; i++)\r\n                        {\r\n                            chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];\r\n                        }\r\n                        string personalAccessTokenName = new string(chars);\r\n                        personalAccessTokenName = \"SCMKIT-\" + personalAccessTokenName;\r\n\r\n\r\n                        string body = \"name=\" + personalAccessTokenName + \"&scopes[]=api&scopes[]=read_repository&scopes[]=write_repository\";\r\n                        streamWriter.Write(body);\r\n                    }\r\n\r\n                    // get the response and the access token\r\n                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();\r\n                    var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                    string result = streamReader.ReadToEnd();\r\n\r\n                    // create table header\r\n                    string tableHeader = string.Format(\"{0,5} | {1,12} | {2,30}\", \"ID\", \"Name\", \"Token\");\r\n                    Console.WriteLine(tableHeader);\r\n                    Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n\r\n                    int startIndexTokenID = result.IndexOf(\"\\\"id\\\":\");\r\n                    int endIndexTokenID = result.IndexOf(\"\\\"name\\\":\");\r\n                    string tokenID = result.Substring(startIndexTokenID + \"\\\"id\\\":\".Length, endIndexTokenID - startIndexTokenID - \"\\\"name\\\"\".Length);\r\n\r\n                    int startIndexTokenName = result.IndexOf(\"\\\"name\\\":\");\r\n                    int endIndexTokenName = result.IndexOf(\"\\\"revoked\\\":\");\r\n                    string tokenName = result.Substring(startIndexTokenName + \"\\\"name\\\":\".Length, endIndexTokenName - startIndexTokenName - \"\\\"revoked\\\"\".Length).Replace(\"\\\"\", \"\");\r\n\r\n                    int startIndexTokenContent = result.IndexOf(\"\\\"token\\\":\");\r\n                    int endIndexTokenContent = result.IndexOf(\"\\\"}\");\r\n                    string tokenContent = result.Substring(startIndexTokenContent + \"\\\"token\\\":\".Length, endIndexTokenContent - startIndexTokenContent - \"\\\"token\\\":\".Length).Replace(\"\\\"\", \"\");\r\n\r\n\r\n                    Console.WriteLine(\"{0,5} | {1,12} | {2,30}\", tokenID, tokenName, tokenContent);\r\n\r\n\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[+] SUCCESS: The \" + options + \" user personal access token was successfully added.\");\r\n                    Console.WriteLine(\"\");\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (KeyNotFoundException ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: User provided does not exist to create personal access token for. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not create personal access token for user. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/CreateSSHKey.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n    class CreateSSHKey\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"createsshkey\", credential, url, options, system));\r\n\r\n            // dictionary to hold lookup table user ID's and usernames\r\n            Dictionary<string, string> userMapping = new Dictionary<string, string>();\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // proceed with request to add ssh key for given user\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n\r\n\r\n                // perform request to create SSH key\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/user/keys\");\r\n\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"POST\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n\r\n                    // set body and sent request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n\r\n                        // create random key name\r\n                        Random rd = new Random();\r\n                        const string allowedChars = \"ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\r\n                        char[] chars = new char[5];\r\n\r\n                        for (int i = 0; i < 5; i++)\r\n                        {\r\n                            chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];\r\n                        }\r\n                        string sshKeyName = new string(chars);\r\n                        sshKeyName = \"SCMKIT-\" + sshKeyName;\r\n\r\n\r\n                        string json = \"{\\\"\" + \"title\" + \"\\\": \\\"\" + sshKeyName + \"\\\",\\\"key\\\":\\\"\" + options + \"\\\"}\";\r\n                        streamWriter.Write(json);\r\n                    }\r\n\r\n                    // get the response and the access token\r\n                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();\r\n                    var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                    string result = streamReader.ReadToEnd();\r\n\r\n\r\n                    // create table header\r\n                    string tableHeader = string.Format(\"{0,12} | {1,15}\", \"SSH Key ID\", \"SSH Key Name\");\r\n                    Console.WriteLine(tableHeader);\r\n                    Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                    int startIndexTokenID = result.IndexOf(\"\\\"id\\\":\");\r\n                    int endIndexTokenID = result.IndexOf(\"\\\"title\\\":\");\r\n                    string tokenID = result.Substring(startIndexTokenID + \"\\\"id\\\":\".Length, endIndexTokenID - startIndexTokenID - \"\\\"id\\\"\".Length);\r\n                    tokenID = tokenID.Replace(\"\\\"\", \"\");\r\n                    tokenID = tokenID.Replace(\",\", \"\");\r\n\r\n                    int startIndexTokenName = result.IndexOf(\"\\\"title\\\":\");\r\n                    int endIndexTokenName = result.IndexOf(\"\\\"created_at\\\":\");\r\n                    string tokenName = result.Substring(startIndexTokenName + \"\\\"title\\\":\".Length, endIndexTokenName - startIndexTokenName - \"\\\"title\\\"\".Length).Replace(\"\\\"\", \"\");\r\n                    tokenName = tokenName.Replace(\",\", \"\");\r\n\r\n\r\n\r\n                    Console.WriteLine(\"{0,12} | {1,15}\", tokenID, tokenName);\r\n\r\n\r\n\r\n\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[+] SUCCESS: The user SSH key was successfully added.\");\r\n                    Console.WriteLine(\"\");\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (KeyNotFoundException ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: User provided does not exist to create SSH key for. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not create SSH key for user. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/FileSearch.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing Newtonsoft.Json;\r\nusing GitLabApiClient;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n\r\n\r\n    // custom class to handle the JSON output of file search result\r\n    public class fileSearchResult\r\n    {\r\n\r\n        public string id { get; set; }\r\n        public string name { get; set; }\r\n        public string type { get; set; }\r\n        public string path { get; set; }\r\n        public string mode { get; set; }\r\n\r\n\r\n        public fileSearchResult()\r\n        {\r\n\r\n        }\r\n\r\n    }\r\n\r\n    class FileSearch\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"searchfile\", credential, url, options, system));\r\n\r\n            // lists to hold project ID's and mappings\r\n            List<string> listOfProjectIds = new List<string>();\r\n            Dictionary<string, string> projectMapping = new Dictionary<string, string>();\r\n\r\n\r\n            try\r\n            {\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                // auth to GitLab and get list of all projects\r\n                Task<GitLabClient> authTask = library.GitLabUtils.AuthToGitLabAsync(credential, url);\r\n                GitLabClient client = authTask.Result;\r\n                var projects = await client.Projects.GetAsync();\r\n\r\n                foreach (var project in projects)\r\n                {\r\n\r\n                    listOfProjectIds.Add(project.Id.ToString());\r\n                    projectMapping.Add(project.Id.ToString(), project.WebUrl);\r\n\r\n                }\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // proceed with performing the search since we have all the project ID's and mappings\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n\r\n                int searchMatchCount = 0;\r\n\r\n                // perform the search for files with search term against each project using the project search API\r\n                foreach (string projectToSearch in listOfProjectIds)\r\n                {\r\n                    var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/projects/\" + projectToSearch + \"/repository/tree?recursive=true&per_page=100\");\r\n                    if (webRequest != null)\r\n                    {\r\n                        // set header values\r\n                        webRequest.Method = \"GET\";\r\n                        webRequest.ContentType = \"application/json\";\r\n                        webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                        // if we need to pass the token obtained from the username/password auth\r\n                        if (credential.Contains(\":\"))\r\n                        {\r\n                            webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                        }\r\n                        // if user just specified personal access token\r\n                        else\r\n                        {\r\n                            webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                        }\r\n\r\n                        // get web response\r\n                        WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                        string content;\r\n                        var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                        content = reader.ReadToEnd();\r\n\r\n\r\n                        // parse the JSON output and display results\r\n                        List<fileSearchResult> searchResults = JsonConvert.DeserializeObject<List<fileSearchResult>>(content);\r\n                        foreach (fileSearchResult item in searchResults)\r\n                        {\r\n                            if (item.name.ToLower().Contains(options.ToLower()))\r\n                            {\r\n                                if (item.type.ToLower().Equals(\"blob\"))\r\n                                {\r\n                                    Console.WriteLine(\"\\n[>] URL: \" + projectMapping[projectToSearch] + \"/\" + item.path);\r\n                                    searchMatchCount++;\r\n                                }\r\n                            }\r\n\r\n\r\n                        }\r\n\r\n                    }\r\n                }\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"Total number of items matching file search: \" + searchMatchCount);\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform file search for search term given. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n\r\n\r\n            }\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/ListPAT.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing Newtonsoft.Json;\r\nusing GitLabApiClient;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n\r\n    // custom class to handle the JSON output of personal access token\r\n    public class patResult\r\n    {\r\n\r\n        public int id { get; set; }\r\n        public string name { get; set; }\r\n        public bool revoked { get; set; }\r\n        public string createdAt { get; set; }\r\n        public string[] scopes { get; set; }\r\n        public int user_id { get; set; }\r\n        public bool active { get; set; }\r\n        public string expires_at { get; set; }\r\n\r\n\r\n        public patResult()\r\n        {\r\n\r\n        }\r\n\r\n    }\r\n    class ListPAT\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listpat\", credential, url, options, system));\r\n\r\n            // dicationary to hold lookup table user ID's and usernames\r\n            Dictionary<string, string> userMapping = new Dictionary<string, string>();\r\n\r\n            try\r\n            {\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                // auth to GitLab and get list of all users\r\n                Task<GitLabClient> authTask = library.GitLabUtils.AuthToGitLabAsync(credential, url);\r\n                GitLabClient client = authTask.Result;\r\n                var users = await client.Users.GetAsync();\r\n\r\n                // add associated user and user id to the dictionary for subsequent requests\r\n                foreach (var user in users)\r\n                {\r\n                    userMapping.Add(user.Username, user.Id.ToString());\r\n                }\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n\r\n                // proceed with request to list PATs for the user given\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n                string theUserID = userMapping[options.ToLower()];\r\n\r\n\r\n                // get listing of all personal access tokens for the user\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,5} | {1,20} | {2,10} | {3,50}\", \"ID\", \"Name\", \"Active?\", \"Scopes\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n\r\n                // get personal access tokens for user\r\n                var webRequestPersonalAccessTokens = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/personal_access_tokens?user_id=\" + theUserID);\r\n                if (webRequestPersonalAccessTokens != null)\r\n                {\r\n                    // set header values\r\n                    webRequestPersonalAccessTokens.Method = \"GET\";\r\n                    webRequestPersonalAccessTokens.ContentType = \"application/json\";\r\n                    webRequestPersonalAccessTokens.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequestPersonalAccessTokens.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequestPersonalAccessTokens.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponsePersonalAccessToken = await webRequestPersonalAccessTokens.GetResponseAsync();\r\n                    string contentPersonalAccessToken;\r\n                    var readerPersonalAccessToken = new StreamReader(myWebResponsePersonalAccessToken.GetResponseStream());\r\n                    contentPersonalAccessToken = readerPersonalAccessToken.ReadToEnd();\r\n\r\n                    // if more than 1 page, we need to track what next URL will be\r\n                    string nextURL = \"\";\r\n\r\n\r\n                    // parse the JSON output and display result to retrieve the PAT\r\n                    List<patResult> patResults = JsonConvert.DeserializeObject<List<patResult>>(contentPersonalAccessToken);\r\n                    foreach (patResult item in patResults)\r\n                    {\r\n\r\n                        string scopesToList = \"\";\r\n                        foreach (string a in item.scopes)\r\n                        {\r\n                            scopesToList += a + \", \";\r\n                        }\r\n\r\n                        scopesToList = scopesToList.Substring(0, scopesToList.Length - 2);\r\n\r\n\r\n                        // only display an active PAT\r\n                        if (item.active == true)\r\n                        {\r\n                            Console.WriteLine(\"{0,5} | {1,20} | {2,10} | {3,50}\", item.id, item.name, item.active, scopesToList);\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    // figure out if there are more results due to paging and we need to send another request for the next page\r\n                    for (int i = 0; i < myWebResponsePersonalAccessToken.Headers.Count; ++i)\r\n                    {\r\n\r\n                        string[] splitValues = myWebResponsePersonalAccessToken.Headers[i].Split(',');\r\n                        foreach (string val in splitValues)\r\n                        {\r\n\r\n                            if (val.Contains(\"rel=\\\"next\\\"\"))\r\n                            {\r\n                                nextURL = val;\r\n                                nextURL = nextURL.Replace(\">; rel=\\\"next\\\"\", \"\");\r\n                                nextURL = nextURL.Replace(\"<\", \"\");\r\n\r\n                            }\r\n\r\n                        }\r\n                    }\r\n\r\n                    // make subsequent requests if more than 1 page\r\n                    if (!nextURL.Equals(\"\"))\r\n                    {\r\n                        await makeSubsequentRequestAsync(credential, nextURL, options, accessToken);\r\n                    }\r\n\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (KeyNotFoundException ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: User provided does not exist to list personal acccess tokens. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not list personal access token for user. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n        // this is just placeholder for making more than 1 request due to paging of results. will have better global solution at some point than this band-aid\r\n        public static async Task makeSubsequentRequestAsync(string credential, string url, string options, string token)\r\n        {\r\n\r\n            try\r\n            {\r\n\r\n                string accessToken = token;\r\n\r\n\r\n                // get personal access tokens for user\r\n                var webRequestPersonalAccessTokens = (HttpWebRequest)System.Net.WebRequest.Create(url);\r\n                if (webRequestPersonalAccessTokens != null)\r\n                {\r\n                    // set header values\r\n                    webRequestPersonalAccessTokens.Method = \"GET\";\r\n                    webRequestPersonalAccessTokens.ContentType = \"application/json\";\r\n                    webRequestPersonalAccessTokens.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequestPersonalAccessTokens.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequestPersonalAccessTokens.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponsePersonalAccessToken = await webRequestPersonalAccessTokens.GetResponseAsync();\r\n                    string contentPersonalAccessToken;\r\n                    var readerPersonalAccessToken = new StreamReader(myWebResponsePersonalAccessToken.GetResponseStream());\r\n                    contentPersonalAccessToken = readerPersonalAccessToken.ReadToEnd();\r\n\r\n\r\n                    string nextURL = \"\";\r\n\r\n\r\n\r\n                    // parse the JSON output and display result to retrieve the personal access token id(s)\r\n                    List<patResult> patResults = JsonConvert.DeserializeObject<List<patResult>>(contentPersonalAccessToken);\r\n                    foreach (patResult item in patResults)\r\n                    {\r\n\r\n                        string scopesToList = \"\";\r\n                        foreach (string a in item.scopes)\r\n                        {\r\n                            scopesToList += a + \", \";\r\n                        }\r\n\r\n                        scopesToList = scopesToList.Substring(0, scopesToList.Length - 2);\r\n\r\n                        // only display an active PAT\r\n                        if (item.active == true)\r\n                        {\r\n                            Console.WriteLine(\"{0,5} | {1,20} | {2,10} | {3,50}\", item.id, item.name, item.active, scopesToList);\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    // figure out if there are more results due to paging and we need to send another request for the next page\r\n                    for (int i = 0; i < myWebResponsePersonalAccessToken.Headers.Count; ++i)\r\n                    {\r\n\r\n                        string[] splitValues = myWebResponsePersonalAccessToken.Headers[i].Split(',');\r\n                        foreach (string val in splitValues)\r\n                        {\r\n\r\n                            if (val.Contains(\"rel=\\\"next\\\"\"))\r\n                            {\r\n                                nextURL = val;\r\n                                nextURL = nextURL.Replace(\">; rel=\\\"next\\\"\", \"\");\r\n                                nextURL = nextURL.Substring(1, nextURL.Length - 1);\r\n                                nextURL = nextURL.Replace(\"<\", \"\");\r\n\r\n                            }\r\n\r\n                        }\r\n                    }\r\n\r\n                    // make subsequent requests if more pages\r\n                    if (!nextURL.Equals(\"\"))\r\n                    {\r\n                        await makeSubsequentRequestAsync(credential, nextURL, options, accessToken);\r\n                    }\r\n\r\n\r\n                }\r\n\r\n            }\r\n            catch (KeyNotFoundException ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: User provided does not exist to list personal acccess tokens. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not list personal access token for user. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/ListSSHKeys.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Linq;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n    class ListSSHKeys\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listsshkey\", credential, url, options, system));\r\n\r\n            // dictionary to hold lookup table user ID's and usernames\r\n            Dictionary<string, string> userMapping = new Dictionary<string, string>();\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,12} | {1,25} | {2,20}\", \"SSH Key ID\", \"SSH Key Value\", \"Title\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // proceed with request to list ssh keys for given user\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n\r\n\r\n                // perform request to list SSH keys\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/user/keys\");\r\n\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n\r\n\r\n                    // get the response and the access token\r\n                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();\r\n                    var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                    string result = streamReader.ReadToEnd();\r\n\r\n\r\n                    // get all instances of the SSH key id\r\n                    IEnumerable<int> startingIndexesID = library.Utils.AllIndexesOf(result, \"\\\"id\\\":\");\r\n                    IEnumerable<int> endingIndexesID = library.Utils.AllIndexesOf(result, \"\\\"title\\\":\");\r\n\r\n                    List<string> listOfIndexIDs = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesID.Count(); i++)\r\n                    {\r\n\r\n                        string sshKeyID = \"\";\r\n                        sshKeyID = result.Substring(startingIndexesID.ElementAt(i) + \"\\\"id\\\":\".Length, endingIndexesID.ElementAt(i) - startingIndexesID.ElementAt(i) - \"\\\"id\\\"\".Length);\r\n                        sshKeyID = sshKeyID.Replace(\"\\\"\", \"\");\r\n                        sshKeyID = sshKeyID.Replace(\",\", \"\");\r\n                        listOfIndexIDs.Add(sshKeyID);\r\n\r\n                    }\r\n\r\n\r\n                    // get all instances of the SSH key value\r\n                    IEnumerable<int> startingIndexesValue = library.Utils.AllIndexesOf(result, \"\\\"key\\\":\");\r\n                    IEnumerable<int> endingIndexesValue = library.Utils.AllIndexesOf(result, \"\\\"}\");\r\n\r\n                    List<string> listOfIndexValues = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesValue.Count(); i++)\r\n                    {\r\n\r\n                        string sshKeyValue = \"\";\r\n                        sshKeyValue = result.Substring(startingIndexesValue.ElementAt(i) + \"\\\"key\\\":\".Length, endingIndexesValue.ElementAt(i) - startingIndexesValue.ElementAt(i) - \"\\\"key\\\"\".Length);\r\n                        sshKeyValue = sshKeyValue.Replace(\"\\\"\", \"\");\r\n                        sshKeyValue = sshKeyValue.Replace(\",\", \"\");\r\n                        listOfIndexValues.Add(sshKeyValue);\r\n\r\n\r\n                    }\r\n\r\n\r\n\r\n                    // get all instances of the SSH key title\r\n                    IEnumerable<int> startingIndexesTitle = library.Utils.AllIndexesOf(result, \"\\\"title\\\":\");\r\n                    IEnumerable<int> endingIndexesTitle = library.Utils.AllIndexesOf(result, \"\\\"created_at\\\":\");\r\n\r\n                    List<string> listOfIndexTitles = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesTitle.Count(); i++)\r\n                    {\r\n\r\n                        string sshKeyTitle = \"\";\r\n                        sshKeyTitle = result.Substring(startingIndexesTitle.ElementAt(i) + \"\\\"title\\\":\".Length, endingIndexesTitle.ElementAt(i) - startingIndexesTitle.ElementAt(i) - \"\\\"ketitley\\\"\".Length);\r\n                        sshKeyTitle = sshKeyTitle.Replace(\"\\\"\", \"\");\r\n                        sshKeyTitle = sshKeyTitle.Replace(\",\", \"\");\r\n                        listOfIndexTitles.Add(sshKeyTitle);\r\n\r\n\r\n                    }\r\n\r\n\r\n                    // iterate through and print the ssh key ID's and contents\r\n                    for (int i = 0; i < listOfIndexIDs.Count(); i++)\r\n                    {\r\n\r\n                        string[] sshKeyArray = listOfIndexValues[i].Split(' ');\r\n                        string justSSHKey = sshKeyArray[1].Substring(sshKeyArray[1].Length - 20, 20);\r\n\r\n\r\n                        Console.WriteLine(\"{0,12} | {1,25} | {2,20}\", listOfIndexIDs[i], \".....\" + justSSHKey, listOfIndexTitles[i]);\r\n                    }\r\n\r\n\r\n\r\n\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not list SSH keys for user. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/Privs.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing Newtonsoft.Json;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n\r\n    // custom class to handle the JSON output of API token permissions\r\n    public class apiPermissions\r\n    {\r\n        public string id { get; set; }\r\n        public string name { get; set; }\r\n        public bool revoked { get; set; }\r\n        public string createdAt { get; set; }\r\n        public string[] scopes { get; set; }\r\n        public string user_id { get; set; }\r\n        public bool active { get; set; }\r\n        public string expiresAt { get; set; }\r\n\r\n        public apiPermissions()\r\n        {\r\n\r\n        }\r\n\r\n\r\n    }\r\n\r\n\r\n    class Privs\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            Dictionary<string, string> valuePairs = new Dictionary<string, string>();\r\n            valuePairs.Add(\"api\", \"Read-write for the complete API, including all groups and projects, the Container Registry, and the Package Registry.\");\r\n            valuePairs.Add(\"read_user\", \"Read-only for endpoints under /users. Essentially, access to any of the GET requests in the Users API.\");\r\n            valuePairs.Add(\"read_api\", \"Read-only for the complete API, including all groups and projects, the Container Registry, and the Package Registry.\");\r\n            valuePairs.Add(\"read_repository\", \"\tRead-only (pull) for the repository through git clone.\");\r\n            valuePairs.Add(\"write_repository\", \"Read-write (pull, push) for the repository through git clone. Required for accessing Git repositories over HTTP when 2FA is enabled.\");\r\n            valuePairs.Add(\"read_registry\", \"Read-only (pull) for Container Registry images if a project is private and authorization is required.\");\r\n            valuePairs.Add(\"write_registry\", \"Read-write (push) for Container Registry images if a project is private and authorization is required.\");\r\n            valuePairs.Add(\"sudo\", \"API actions as any user in the system (if the authenticated user is an administrator).\");\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"privs\", credential, url, options, system));\r\n            List<String> listOfPermissions = new List<String>();\r\n\r\n            // if username/password auth being used\r\n            if (credential.Contains(\":\"))\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Privs module only supports API key authentication to determine privs of the API key given.\");\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n            // if token auth being used\r\n            else\r\n            {\r\n\r\n                try\r\n                {\r\n                    ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                    ServicePointManager.Expect100Continue = true;\r\n                    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                    await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                    // get the users id to be passed in subsequent request\r\n                    string userId = \"\";\r\n                    var webRequestUserID = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/user\");\r\n                    if (webRequestUserID != null)\r\n                    {\r\n                        // set header values\r\n                        webRequestUserID.Method = \"GET\";\r\n                        webRequestUserID.ContentType = \"application/json\";\r\n                        webRequestUserID.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                        webRequestUserID.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                        // get web response\r\n                        WebResponse myWebResponseUserID = await webRequestUserID.GetResponseAsync();\r\n                        string contentUserID;\r\n                        var readerUserID = new StreamReader(myWebResponseUserID.GetResponseStream());\r\n                        contentUserID = readerUserID.ReadToEnd();\r\n\r\n                        int startIndex = contentUserID.IndexOf(\"\\\"id\\\":\");\r\n                        int endIndex = contentUserID.IndexOf(\"\\\"name\\\":\");\r\n                        userId = contentUserID.Substring(startIndex + \"\\\"id\\\":\".Length, endIndex - startIndex - \"\\\"name\\\"\".Length);\r\n                        myWebResponseUserID.Close();\r\n\r\n                    }\r\n\r\n\r\n                    // create table header\r\n                    string tableHeader = string.Format(\"{0,20} | {1,10} | {2,20} | {3,70}\", \"Token Name\", \"Active?\", \"Privilege\", \"Description\");\r\n                    Console.WriteLine(tableHeader);\r\n                    Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n\r\n                    // get personal access tokens for user\r\n                    var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/personal_access_tokens\");\r\n                    if (webRequest != null)\r\n                    {\r\n                        // set header values\r\n                        webRequest.Method = \"GET\";\r\n                        webRequest.ContentType = \"application/json\";\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                        webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                        // get web response\r\n                        WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                        string content;\r\n                        var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                        content = reader.ReadToEnd();\r\n\r\n                        // if more than 1 page, we need to track what next URL will be\r\n                        string nextURL = \"\";\r\n\r\n\r\n                        // parse the JSON output and display results\r\n                        List<apiPermissions> apiPerms = JsonConvert.DeserializeObject<List<apiPermissions>>(content);\r\n\r\n                        foreach (apiPermissions item in apiPerms)\r\n                        {\r\n                            string keyName = item.name;\r\n                            string uid = item.user_id;\r\n\r\n\r\n                            // if user is not filtering and just wants to see there tokens\r\n                            if (options.Equals(\"\") && uid.Equals(userId))\r\n                            {\r\n\r\n                                if (uid.Equals(userId))\r\n                                {\r\n                                    string[] theScopes = item.scopes;\r\n                                    for (int i = 0; i < theScopes.Length; i++)\r\n                                    {\r\n                                        string theKeyScope = theScopes[i];\r\n\r\n                                        // only display an active PAT\r\n                                        if (item.active == true)\r\n                                        {\r\n\r\n                                            Console.WriteLine(\"{0,20} | {1,10} | {2,20} | {3,70}\", item.name, item.active, theKeyScope, valuePairs[theKeyScope]);\r\n                                        }\r\n                                    }\r\n                                }\r\n                            }\r\n\r\n                            // if user is filtering on specific PAT\r\n                            if (!options.Equals(\"\"))\r\n                            {\r\n\r\n                                string[] theScopes = item.scopes;\r\n                                for (int i = 0; i < theScopes.Length; i++)\r\n                                {\r\n                                    string theKeyScope = theScopes[i];\r\n\r\n                                    // if user is filtering for specific PAT\r\n                                    if (!options.Equals(\"\"))\r\n                                    {\r\n                                        if (options.ToLower().Equals(keyName.ToLower()))\r\n                                        {\r\n\r\n                                            // only display an active PAT\r\n                                            if (item.active == true)\r\n                                            {\r\n                                                Console.WriteLine(\"{0,20} | {1,10} | {2,20} | {3,70}\", item.name, item.active, theKeyScope, valuePairs[theKeyScope]);\r\n                                            }\r\n                                        }\r\n                                    }\r\n\r\n                                    // if user just wants to see all PATs it can see\r\n                                    else\r\n                                    {\r\n                                        // only display an active PAT\r\n                                        if (item.active == true)\r\n                                        {\r\n                                            Console.WriteLine(\"{0,20} | {1,10} | {2,20} | {3,70}\", item.name, item.active, theKeyScope, valuePairs[theKeyScope]);\r\n                                        }\r\n                                    }\r\n\r\n\r\n                                }\r\n                            }\r\n\r\n                            // figure out if there are more results due to paging and we need to send another request for the next page\r\n                            for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                            {\r\n\r\n                                string[] splitValues = myWebResponse.Headers[i].Split(',');\r\n                                foreach (string val in splitValues)\r\n                                {\r\n\r\n                                    if (val.Contains(\"rel=\\\"next\\\"\"))\r\n                                    {\r\n                                        nextURL = val;\r\n                                        nextURL = nextURL.Replace(\">; rel=\\\"next\\\"\", \"\");\r\n                                        nextURL = nextURL.Substring(1, nextURL.Length - 1);\r\n\r\n                                    }\r\n\r\n                                }\r\n                            }\r\n\r\n                            // make subsequent requests if more than 1 page\r\n                            if (!nextURL.Equals(\"\"))\r\n                            {\r\n                                await makeSubsequentRequestAsync(credential, nextURL, options, userId, valuePairs);\r\n                            }\r\n                        }\r\n\r\n                    }\r\n\r\n                }\r\n\r\n                catch (Exception ex)\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Could not retrieve listing of privileges for current API token. Exception: \" + ex.ToString());\r\n                    Console.WriteLine(\"\");\r\n                }\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n\r\n        // this is just placeholder for making more than 1 request due to paging of results. will have better global solution at some point than this band-aid\r\n        public static async Task makeSubsequentRequestAsync(string credential, string url, string options, string userId, Dictionary<string, string> valuePairs)\r\n        {\r\n\r\n            try\r\n            {\r\n\r\n                string accessToken = \"\";\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n\r\n\r\n                // get personal access tokens for user\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    string nextURL = \"\";\r\n\r\n\r\n                    // parse the JSON output and display results\r\n                    List<apiPermissions> apiPerms = JsonConvert.DeserializeObject<List<apiPermissions>>(content);\r\n\r\n                    foreach (apiPermissions item in apiPerms)\r\n                    {\r\n                        string keyName = item.name;\r\n                        string uid = item.user_id;\r\n\r\n\r\n                        // if user is not filtering and just wants to see there tokens\r\n                        if (options.Equals(\"\") && uid.Equals(userId))\r\n                        {\r\n\r\n                            if (uid.Equals(userId))\r\n                            {\r\n                                string[] theScopes = item.scopes;\r\n                                for (int i = 0; i < theScopes.Length; i++)\r\n                                {\r\n                                    string theKeyScope = theScopes[i];\r\n\r\n                                    // only display an active PAT\r\n                                    if (item.active == true)\r\n                                    {\r\n                                        Console.WriteLine(\"{0,20} | {1,10} | {2,20} | {3,70}\", item.name, item.active, theKeyScope, valuePairs[theKeyScope]);\r\n                                    }\r\n                                }\r\n                            }\r\n                        }\r\n\r\n                        // if user is filtering on specific PAT\r\n                        if (!options.Equals(\"\"))\r\n                        {\r\n\r\n                            string[] theScopes = item.scopes;\r\n                            for (int i = 0; i < theScopes.Length; i++)\r\n                            {\r\n                                string theKeyScope = theScopes[i];\r\n\r\n                                // if user is filtering for specific PAT\r\n                                if (!options.Equals(\"\"))\r\n                                {\r\n                                    if (options.ToLower().Equals(keyName.ToLower()))\r\n                                    {\r\n                                        // only display an active PAT\r\n                                        if (item.active == true)\r\n                                        {\r\n                                            Console.WriteLine(\"{0,20} | {1,10} | {2,20} | {3,70}\", item.name, item.active, theKeyScope, valuePairs[theKeyScope]);\r\n                                        }\r\n                                    }\r\n                                }\r\n\r\n                                // if user just wants to see all PATs it can see\r\n                                else\r\n                                {\r\n                                    // only display an active PAT\r\n                                    if (item.active == true)\r\n                                    {\r\n                                        Console.WriteLine(\"{0,20} | {1,10} | {2,20} | {3,70}\", item.name, item.active, theKeyScope, valuePairs[theKeyScope]);\r\n                                    }\r\n                                }\r\n\r\n\r\n                            }\r\n\r\n\r\n\r\n                            // figure out if there are more results due to paging and we need to send another request for the next page\r\n                            for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                            {\r\n\r\n                                string[] splitValues = myWebResponse.Headers[i].Split(',');\r\n                                foreach (string val in splitValues)\r\n                                {\r\n\r\n                                    if (val.Contains(\"rel=\\\"next\\\"\"))\r\n                                    {\r\n                                        nextURL = val;\r\n                                        nextURL = nextURL.Replace(\">; rel=\\\"next\\\"\", \"\");\r\n                                        nextURL = nextURL.Substring(1, nextURL.Length - 1);\r\n                                        nextURL = nextURL.Replace(\"<\", \"\");\r\n\r\n                                    }\r\n\r\n                                }\r\n                            }\r\n\r\n                            // make subsequent requests if more pages\r\n                            if (!nextURL.Equals(\"\"))\r\n                            {\r\n                                await makeSubsequentRequestAsync(credential, nextURL, options, userId, valuePairs);\r\n                            }\r\n\r\n\r\n                        }\r\n                    }\r\n                }\r\n\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR:  Could not retrieve listing of privileges for current API token. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/RemoveAdmin.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing GitLabApiClient;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n    class RemoveAdmin\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"removeadmin\", credential, url, options, system));\r\n\r\n            // dicationary to hold lookup table user ID's and usernames\r\n            Dictionary<string, string> userMapping = new Dictionary<string, string>();\r\n\r\n            try\r\n            {\r\n\r\n                // auth to GitLab and get list of all users\r\n                Task<GitLabClient> authTask = library.GitLabUtils.AuthToGitLabAsync(credential, url);\r\n                GitLabClient client = authTask.Result;\r\n                var users = await client.Users.GetAsync();\r\n\r\n                // add associated user and user id to the dictionary for subsequent requests\r\n                foreach (var user in users)\r\n                {\r\n                    userMapping.Add(user.Username, user.Id.ToString());\r\n                }\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                // proceed with request to remove admin permissions for the user given\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n                string theUserID = userMapping[options.ToLower()];\r\n\r\n                // get snippets for user\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/users/\" + theUserID);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"PUT\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n\r\n                    // set body and sent request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n                        string json = \"{\\\"admin\\\":\\\"false\\\"}\";\r\n                        streamWriter.Write(json);\r\n                    }\r\n\r\n                    // get the response and the access token\r\n                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();\r\n                    var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                    string result = streamReader.ReadToEnd();\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[+] SUCCESS: The \" + options + \" user was successfully removed from the admin role.\");\r\n                    Console.WriteLine(\"\");\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (KeyNotFoundException ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: User provided does not exist to remove admin role. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not remove user from admin role. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/RemovePAT.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n    class RemovePAT\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"removepat\", credential, url, options, system));\r\n\r\n\r\n\r\n            try\r\n            {\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                // proceed with request to remove PAT for the user given\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n                // if user didn't specify an ID, display message and return\r\n                if (options.Equals(\"\"))\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Must supply ID of PAT to remove.\");\r\n                    Console.WriteLine(\"\");\r\n                    return;\r\n                }\r\n\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[*] INFO: Revoking personal access token of ID: \" + options);\r\n                Console.WriteLine(\"\");\r\n\r\n                // perform request to remove PAT\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/personal_access_tokens/\" + options);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"DELETE\";\r\n                    webRequest.ContentType = \"application/x-www-form-urlencoded\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n\r\n                    // set body and sent request\r\n                    using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))\r\n                    {\r\n\r\n                        string body = \"\";\r\n                        streamWriter.Write(body);\r\n                    }\r\n\r\n                    // get the response and the access token\r\n                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();\r\n                    var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                    string result = streamReader.ReadToEnd();\r\n\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[+] SUCCESS: The personal access token of ID \" + options + \" was successfully revoked.\");\r\n                    Console.WriteLine(\"\");\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (KeyNotFoundException ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: User provided does not exist to revoke personal access token. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not revoke personal access token for user. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/RemoveSSHKey.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\n\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n    class RemoveSSHKey\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"removesshkey\", credential, url, options, system));\r\n\r\n            // dictionary to hold lookup table user ID's and usernames\r\n            Dictionary<string, string> userMapping = new Dictionary<string, string>();\r\n\r\n            try\r\n            {\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n\r\n                // proceed with request to remove ssh key for given user\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n                // if user didn't specify an ID, display message and return\r\n                if (options.Equals(\"\"))\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Must supply ID of SSH key to remove.\");\r\n                    Console.WriteLine(\"\");\r\n                    return;\r\n                }\r\n\r\n\r\n                // perform request to remove SSH key\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/user/keys/\" + options);\r\n\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"DELETE\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n\r\n                    // get the response and the access token\r\n                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();\r\n                    var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                    string result = streamReader.ReadToEnd();\r\n\r\n\r\n                    // if we got 204 response, SSH key was removed\r\n                    if (httpResponse.StatusCode.ToString().ToLower().Equals(\"nocontent\"))\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[+] SUCCESS: The SSH key of ID \" + options + \" was successfully revoked.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"\");\r\n                        Console.WriteLine(\"[-] ERROR: There was an error revoking the SSH key.\");\r\n                        Console.WriteLine(\"\");\r\n                    }\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (KeyNotFoundException ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: User provided does not exist to remove SSH key for. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not remove SSH key for user. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/RepoList.cs",
    "content": "﻿using System;\r\nusing System.Threading.Tasks;\r\nusing GitLabApiClient;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n    class RepoList\r\n    {\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listrepo\", credential, url, options, system));\r\n\r\n            try\r\n            {\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                // auth to GitLab and get list of all projects\r\n                Task<GitLabClient> authTask = library.GitLabUtils.AuthToGitLabAsync(credential, url);\r\n                GitLabClient client = authTask.Result;\r\n                var projects = await client.Projects.GetAsync();\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,40} | {1,10} | {2,50}\", \"Name\", \"Visibility\", \"URL\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n                foreach (var project in projects)\r\n                {\r\n\r\n                    if (options.ToLower().Equals(\"private\") && project.Visibility.ToString().Equals(\"Private\"))\r\n                    {\r\n                        Console.WriteLine(\"{0,40} | {1,10} | {2,50}\", project.Name, project.Visibility, project.WebUrl);\r\n\r\n                    }\r\n                    else if (options.ToLower().Equals(\"public\") && project.Visibility.ToString().Equals(\"Public\"))\r\n                    {\r\n                        Console.WriteLine(\"{0,40} | {1,10} | {2,50}\", project.Name, project.Visibility, project.WebUrl);\r\n                    }\r\n                    else if (options.ToLower().Equals(\"internal\") && project.Visibility.ToString().Equals(\"Internal\"))\r\n                    {\r\n                        Console.WriteLine(\"{0,40} | {1,10} | {2,50}\", project.Name, project.Visibility, project.WebUrl);\r\n                    }\r\n                    else if (options.Equals(\"\"))\r\n                    {\r\n                        Console.WriteLine(\"{0,40} | {1,10} | {2,50}\", project.Name, project.Visibility, project.WebUrl);\r\n                    }\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not retrieve listing of repos. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n        }\r\n\r\n\r\n    }\r\n\r\n}"
  },
  {
    "path": "SCMKit/modules/gitlab/RepoSearch.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Linq;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n    class RepoSearch\r\n    {\r\n        private static int searchMatchCount = 0;\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"searchrepo\", credential, url, options, system));\r\n\r\n\r\n\r\n            try\r\n            {\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,40} | {1,10} | {2,50}\", \"Name\", \"Visibility\", \"URL\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n\r\n                // proceed with repo search\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/search?scope=projects&search=\" + options);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string result;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    result = reader.ReadToEnd();\r\n\r\n\r\n                    // get all instances of the id\r\n                    IEnumerable<int> startingIndexesID = AllIndexesOf(result, \"[{\\\"id\\\":\", \",{\\\"id\\\":\");\r\n                    IEnumerable<int> endingIndexesID = library.Utils.AllIndexesOf(result, \"\\\"description\\\":\");\r\n\r\n                    List<string> listOfIDs = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesID.Count(); i++)\r\n                    {\r\n\r\n                        string theID = \"\";\r\n                        theID = result.Substring(startingIndexesID.ElementAt(i) + \"[{\\\"id\\\":\".Length, endingIndexesID.ElementAt(i) - startingIndexesID.ElementAt(i) - \"[{\\\"id\\\":\".Length);\r\n                        theID = theID.Replace(\",\", \"\");\r\n                        theID = theID.Replace(\" \", \"\");\r\n                        listOfIDs.Add(theID);\r\n\r\n                    }\r\n\r\n\r\n                    // get all instances of the name\r\n                    IEnumerable<int> startingIndexesName = library.Utils.AllIndexesOf(result, \"\\\"name_with_namespace\\\":\");\r\n                    IEnumerable<int> endingIndexesName = library.Utils.AllIndexesOf(result, \"\\\"path_with_namespace\\\":\");\r\n\r\n                    List<string> listOfNames = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesName.Count(); i++)\r\n                    {\r\n\r\n                        string theName = \"\";\r\n                        theName = result.Substring(startingIndexesName.ElementAt(i) + \"\\\"name_with_namespace\\\":\".Length, endingIndexesName.ElementAt(i) - startingIndexesName.ElementAt(i) - \"\\\"name_with_namespace\\\":\".Length);\r\n                        string[] splitNameArray = theName.Split(',');\r\n                        theName = splitNameArray[0];\r\n                        theName = theName.Replace(\"\\\"\", \"\");\r\n                        string[] splitAgain = theName.Split('/');\r\n                        theName = splitAgain[1];\r\n                        theName.TrimStart();\r\n                        listOfNames.Add(theName);\r\n\r\n                    }\r\n\r\n\r\n                    // get all instances of the URL\r\n                    IEnumerable<int> startingIndexesURL = library.Utils.AllIndexesOf(result, \"\\\"http_url_to_repo\\\":\");\r\n                    IEnumerable<int> endingIndexesURL = library.Utils.AllIndexesOf(result, \"\\\"readme_url\\\":\");\r\n\r\n                    List<string> listOfURLs = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesURL.Count(); i++)\r\n                    {\r\n                        string theURL = \"\";\r\n                        theURL = result.Substring(startingIndexesURL.ElementAt(i) + \"\\\"http_url_to_repo\\\":\".Length, endingIndexesURL.ElementAt(i) - startingIndexesURL.ElementAt(i) - \"\\\"http_url_to_repo\\\":\".Length);\r\n                        string[] splitURLArray = theURL.Split(',');\r\n                        theURL = splitURLArray[0];\r\n                        theURL = theURL.Replace(\"\\\"\", \"\");\r\n                        listOfURLs.Add(theURL);\r\n                    }\r\n\r\n\r\n                    // print the results\r\n                    for (int i = 0; i < listOfIDs.Count; i++)\r\n                    {\r\n                        string visibility = await library.GitLabUtils.GetGitLabProjectVisibility(credential, accessToken, listOfIDs[i], url);\r\n                        Console.WriteLine(\"{0,40} | {1,10} | {2,50}\", listOfNames[i], visibility, listOfURLs[i]);\r\n                        searchMatchCount++;\r\n                    }\r\n\r\n\r\n                    string nextPage = \"\";\r\n\r\n                    // determine if there are more results and subsequent requests need made\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-next-page\") && myWebResponse.Headers.GetValues(i).Length == 1)\r\n                        {\r\n                            nextPage = myWebResponse.Headers.GetValues(i)[0];\r\n\r\n                        }\r\n\r\n                    }\r\n\r\n                    // if there are more pages, then make subsequent requests\r\n                    if (!nextPage.Equals(\"\"))\r\n                    {\r\n                        await makeSubsequentRequestAsync(credential, url, options, accessToken, nextPage);\r\n                    }\r\n\r\n                }\r\n\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"Total number of items matching repo search: \" + searchMatchCount);\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform repo search for search term given. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n\r\n\r\n            }\r\n\r\n        }\r\n\r\n\r\n\r\n        /**\r\n         * method to get all indexes where a value exists in a string. this one is specialized for ID field of GitLab parsing\r\n         * \r\n         * */\r\n        public static int[] AllIndexesOf(string str, string substrOne, string substrTwo, bool ignoreCase = false)\r\n        {\r\n            if (string.IsNullOrWhiteSpace(str) ||\r\n                string.IsNullOrWhiteSpace(substrOne) ||\r\n                string.IsNullOrWhiteSpace(substrTwo))\r\n            {\r\n                throw new ArgumentException(\"String or substring is not specified.\");\r\n            }\r\n\r\n            var indexes = new List<int>();\r\n            int index = 0;\r\n\r\n            while ((index = str.IndexOf(substrOne, index, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) != -1)\r\n            {\r\n                indexes.Add(index++);\r\n\r\n            }\r\n\r\n            int indexTwo = 0;\r\n\r\n            while ((indexTwo = str.IndexOf(substrTwo, indexTwo, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) != -1)\r\n            {\r\n                indexes.Add(indexTwo++);\r\n\r\n            }\r\n\r\n            return indexes.ToArray();\r\n        }\r\n\r\n\r\n\r\n        // this is just placeholder for making more than 1 request due to paging of results. will have better global solution at some point than this band-aid\r\n        public static async Task makeSubsequentRequestAsync(string credential, string url, string options, string accessToken, string nextPage)\r\n        {\r\n\r\n            try\r\n            {\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // proceed with repo search\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/search?scope=projects&page=\" + nextPage + \"&search=\" + options);\r\n                if (webRequest != null)\r\n                {\r\n\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string result;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    result = reader.ReadToEnd();\r\n\r\n\r\n                    // get all instances of the id\r\n                    IEnumerable<int> startingIndexesID = AllIndexesOf(result, \"[{\\\"id\\\":\", \",{\\\"id\\\":\");\r\n                    IEnumerable<int> endingIndexesID = library.Utils.AllIndexesOf(result, \"\\\"description\\\":\");\r\n\r\n                    List<string> listOfIDs = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesID.Count(); i++)\r\n                    {\r\n\r\n                        string theID = \"\";\r\n                        theID = result.Substring(startingIndexesID.ElementAt(i) + \"[{\\\"id\\\":\".Length, endingIndexesID.ElementAt(i) - startingIndexesID.ElementAt(i) - \"[{\\\"id\\\":\".Length);\r\n                        theID = theID.Replace(\",\", \"\");\r\n                        theID = theID.Replace(\" \", \"\");\r\n                        listOfIDs.Add(theID);\r\n\r\n                    }\r\n\r\n\r\n                    // get all instances of the name\r\n                    IEnumerable<int> startingIndexesName = library.Utils.AllIndexesOf(result, \"\\\"name_with_namespace\\\":\");\r\n                    IEnumerable<int> endingIndexesName = library.Utils.AllIndexesOf(result, \"\\\"path_with_namespace\\\":\");\r\n\r\n                    List<string> listOfNames = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesName.Count(); i++)\r\n                    {\r\n\r\n                        string theName = \"\";\r\n                        theName = result.Substring(startingIndexesName.ElementAt(i) + \"\\\"name_with_namespace\\\":\".Length, endingIndexesName.ElementAt(i) - startingIndexesName.ElementAt(i) - \"\\\"name_with_namespace\\\":\".Length);\r\n                        string[] splitNameArray = theName.Split(',');\r\n                        theName = splitNameArray[0];\r\n                        theName = theName.Replace(\"\\\"\", \"\");\r\n                        string[] splitAgain = theName.Split('/');\r\n                        theName = splitAgain[1];\r\n                        theName.TrimStart();\r\n                        listOfNames.Add(theName);\r\n\r\n                    }\r\n\r\n\r\n                    // get all instances of the URL\r\n                    IEnumerable<int> startingIndexesURL = library.Utils.AllIndexesOf(result, \"\\\"http_url_to_repo\\\":\");\r\n                    IEnumerable<int> endingIndexesURL = library.Utils.AllIndexesOf(result, \"\\\"readme_url\\\":\");\r\n\r\n                    List<string> listOfURLs = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesURL.Count(); i++)\r\n                    {\r\n                        string theURL = \"\";\r\n                        theURL = result.Substring(startingIndexesURL.ElementAt(i) + \"\\\"http_url_to_repo\\\":\".Length, endingIndexesURL.ElementAt(i) - startingIndexesURL.ElementAt(i) - \"\\\"http_url_to_repo\\\":\".Length);\r\n                        string[] splitURLArray = theURL.Split(',');\r\n                        theURL = splitURLArray[0];\r\n                        theURL = theURL.Replace(\"\\\"\", \"\");\r\n                        listOfURLs.Add(theURL);\r\n                    }\r\n\r\n\r\n                    // print the results\r\n                    for (int i = 0; i < listOfIDs.Count; i++)\r\n                    {\r\n                        string visibility = await library.GitLabUtils.GetGitLabProjectVisibility(credential, accessToken, listOfIDs[i], url);\r\n                        Console.WriteLine(\"{0,40} | {1,10} | {2,50}\", listOfNames[i], visibility, listOfURLs[i]);\r\n                        searchMatchCount++;\r\n                    }\r\n\r\n\r\n\r\n                    // determine if there are more results and subsequent requests need made\r\n                    for (int i = 0; i < myWebResponse.Headers.Count; ++i)\r\n                    {\r\n                        if (myWebResponse.Headers.Keys[i].ToString().ToLower().Equals(\"x-next-page\") && myWebResponse.Headers.GetValues(i).Length == 1)\r\n                        {\r\n                            nextPage = myWebResponse.Headers.GetValues(i)[0];\r\n\r\n                        }\r\n\r\n                    }\r\n\r\n\r\n                    // if there are more pages, then make subsequent requests\r\n                    if (!nextPage.Equals(\"\"))\r\n                    {\r\n                        await makeSubsequentRequestAsync(credential, url, options, accessToken, nextPage);\r\n                    }\r\n\r\n\r\n                }\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not perform repo search. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "SCMKit/modules/gitlab/RunnerList.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing System.Linq;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n\r\n\r\n    // custom class to store a runner\r\n    public class aRunner\r\n    {\r\n\r\n        public string id { get; set; }\r\n        public string name { get; set; }\r\n        public string project { get; set; }\r\n\r\n\r\n        public aRunner(string id, string name, string project)\r\n        {\r\n            this.id = id;\r\n            this.name = name;\r\n            this.project = project;\r\n        }\r\n\r\n    }\r\n\r\n\r\n    class RunnerList\r\n    {\r\n\r\n        private static List<aRunner> theRunners = new List<aRunner>();\r\n\r\n        private static List<aRunner> nameAndIDs = new List<aRunner>();\r\n\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listrunner\", credential, url, options, system));\r\n\r\n\r\n\r\n            try\r\n            {\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // proceed with request to list runners accessible for a given user\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,5} | {1,20} | {2,50}\", \"ID\", \"Name\", \"Repo Assigned\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n\r\n                // perform request to get list of runners as we will need the ID of the runners to get more details\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/runners/all\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n\r\n\r\n                    // get the response \r\n                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();\r\n                    var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                    string result = streamReader.ReadToEnd();\r\n\r\n\r\n                    // get all instances of the id field for the id of the runners\r\n                    IEnumerable<int> startingIndexesId = library.Utils.AllIndexesOf(result, \"\\\"id\\\":\");\r\n                    IEnumerable<int> endingIndexesId = library.Utils.AllIndexesOf(result, \"\\\"description\\\":\");\r\n\r\n                    List<string> listOfIds = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesId.Count(); i++)\r\n                    {\r\n\r\n                        string theId = \"\";\r\n                        theId = result.Substring(startingIndexesId.ElementAt(i) + \"\\\"id\\\":\".Length, endingIndexesId.ElementAt(i) - startingIndexesId.ElementAt(i) - \"\\\"id\\\"\".Length);\r\n                        theId = theId.Replace(\"\\\"],\\\"\", \"\");\r\n                        theId = theId.Replace(\"[\", \"\");\r\n                        theId = theId.Replace(\"]\", \"\");\r\n                        theId = theId.Replace(\"\\\"\", \"\");\r\n                        theId = theId.Replace(\",\", \"\");\r\n                        listOfIds.Add(theId);\r\n\r\n                    }\r\n\r\n\r\n                    // get all instances of the name field for the name of the runners\r\n                    IEnumerable<int> startingIndexesName = library.Utils.AllIndexesOf(result, \"\\\"name\\\":\");\r\n                    IEnumerable<int> endingIndexesName = library.Utils.AllIndexesOf(result, \"\\\"online\\\":\");\r\n\r\n                    List<string> listofNames = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesId.Count(); i++)\r\n                    {\r\n\r\n                        string theName = \"\";\r\n                        theName = result.Substring(startingIndexesName.ElementAt(i) + \"\\\"name\\\":\".Length, endingIndexesName.ElementAt(i) - startingIndexesName.ElementAt(i) - \"\\\"name\\\"\".Length);\r\n                        theName = theName.Replace(\"\\\"],\\\"\", \"\");\r\n                        theName = theName.Replace(\"[\", \"\");\r\n                        theName = theName.Replace(\"]\", \"\");\r\n                        theName = theName.Replace(\"\\\"\", \"\");\r\n                        theName = theName.Replace(\",\", \"\");\r\n                        listofNames.Add(theName);\r\n\r\n                    }\r\n\r\n\r\n                    // go through and add the id and name to the runner list array\r\n                    for (int i = 0; i < listOfIds.Count(); i++)\r\n                    {\r\n                        nameAndIDs.Add(new aRunner(listOfIds[i], listofNames[i], \"\"));\r\n\r\n                    }\r\n\r\n\r\n                    // get details of each runner\r\n                    for (int i = 0; i < nameAndIDs.Count(); i++)\r\n                    {\r\n\r\n                        GetRunnerDetails(credential, url, nameAndIDs[i].id, accessToken, nameAndIDs[i].name);\r\n\r\n                    }\r\n\r\n\r\n                    // print the details of each runner\r\n                    for (int i = 0; i < theRunners.Count(); i++)\r\n                    {\r\n                        // as long as projects assigned is not blank, display\r\n                        if (!theRunners[i].project.Equals(\"\"))\r\n                        {\r\n                            Console.WriteLine(\"{0,5} | {1,20} | {2,50}\", theRunners[i].id, theRunners[i].name, theRunners[i].project);\r\n                        }\r\n\r\n\r\n\r\n                    }\r\n\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                // if user is not permitted to list all runners, then just list runners owned by current user\r\n                if (ex.Message.Contains(\"(403) Forbidden\"))\r\n                {\r\n                    await getOwnedRunners(credential, url, options, \"gitlab\");\r\n                }\r\n\r\n                // otherwise display normal error message and return\r\n                else\r\n                {\r\n                    Console.WriteLine(\"\");\r\n                    Console.WriteLine(\"[-] ERROR: Could not get listing of all GitLab runners. Exception: \" + ex.ToString());\r\n                    Console.WriteLine(\"\");\r\n                }\r\n                \r\n\r\n\r\n            }\r\n\r\n        }\r\n\r\n        // get runners owned by current user (non-admin)\r\n        public static async Task getOwnedRunners(string credential, string url, string options, string system)\r\n        {\r\n\r\n            try\r\n            {\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                // proceed with request to list runners accessible for a given user\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n\r\n\r\n                // perform request to get list of runners as we will need the ID of the runners to get more details\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/runners\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n\r\n\r\n                    // get the response \r\n                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();\r\n                    var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                    string result = streamReader.ReadToEnd();\r\n\r\n\r\n                    // get all instances of the id field for the id of the runners\r\n                    IEnumerable<int> startingIndexesId = library.Utils.AllIndexesOf(result, \"\\\"id\\\":\");\r\n                    IEnumerable<int> endingIndexesId = library.Utils.AllIndexesOf(result, \"\\\"description\\\":\");\r\n\r\n                    List<string> listOfIds = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesId.Count(); i++)\r\n                    {\r\n\r\n                        string theId = \"\";\r\n                        theId = result.Substring(startingIndexesId.ElementAt(i) + \"\\\"id\\\":\".Length, endingIndexesId.ElementAt(i) - startingIndexesId.ElementAt(i) - \"\\\"id\\\"\".Length);\r\n                        theId = theId.Replace(\"\\\"],\\\"\", \"\");\r\n                        theId = theId.Replace(\"[\", \"\");\r\n                        theId = theId.Replace(\"]\", \"\");\r\n                        theId = theId.Replace(\"\\\"\", \"\");\r\n                        theId = theId.Replace(\",\", \"\");\r\n                        listOfIds.Add(theId);\r\n\r\n                    }\r\n\r\n\r\n                    // get all instances of the name field for the name of the runners\r\n                    IEnumerable<int> startingIndexesName = library.Utils.AllIndexesOf(result, \"\\\"name\\\":\");\r\n                    IEnumerable<int> endingIndexesName = library.Utils.AllIndexesOf(result, \"\\\"online\\\":\");\r\n\r\n                    List<string> listofNames = new List<string>();\r\n\r\n                    for (int i = 0; i < startingIndexesId.Count(); i++)\r\n                    {\r\n\r\n                        string theName = \"\";\r\n                        theName = result.Substring(startingIndexesName.ElementAt(i) + \"\\\"name\\\":\".Length, endingIndexesName.ElementAt(i) - startingIndexesName.ElementAt(i) - \"\\\"name\\\"\".Length);\r\n                        theName = theName.Replace(\"\\\"],\\\"\", \"\");\r\n                        theName = theName.Replace(\"[\", \"\");\r\n                        theName = theName.Replace(\"]\", \"\");\r\n                        theName = theName.Replace(\"\\\"\", \"\");\r\n                        theName = theName.Replace(\",\", \"\");\r\n                        listofNames.Add(theName);\r\n\r\n                    }\r\n\r\n\r\n                    // go through and add the id and name to the runner list array\r\n                    for (int i = 0; i < listOfIds.Count(); i++)\r\n                    {\r\n                        nameAndIDs.Add(new aRunner(listOfIds[i], listofNames[i], \"\"));\r\n\r\n                    }\r\n\r\n\r\n                    // get details of each runner\r\n                    for (int i = 0; i < nameAndIDs.Count(); i++)\r\n                    {\r\n\r\n                        GetRunnerDetails(credential, url, nameAndIDs[i].id, accessToken, nameAndIDs[i].name);\r\n\r\n                    }\r\n\r\n\r\n                    // print the details of each runner\r\n                    for (int i = 0; i < theRunners.Count(); i++)\r\n                    {\r\n                        // as long as projects assigned is not blank, display\r\n                        if (!theRunners[i].project.Equals(\"\"))\r\n                        {\r\n                            Console.WriteLine(\"{0,5} | {1,20} | {2,50}\", theRunners[i].id, theRunners[i].name, theRunners[i].project);\r\n                        }\r\n\r\n\r\n\r\n                    }\r\n\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not get listing of GitLab runners. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n\r\n\r\n            }\r\n\r\n        }\r\n\r\n\r\n        // get the details for a runner based on ID\r\n        public static void GetRunnerDetails(string credential, string url, string id, string accessToken, string name)\r\n        {\r\n\r\n            try\r\n            {\r\n\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n\r\n                // perform request to get runner details by ID\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/runners/\" + id);\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n\r\n\r\n                    // get the response \r\n                    var httpResponse = (HttpWebResponse)webRequest.GetResponse();\r\n                    var streamReader = new StreamReader(httpResponse.GetResponseStream());\r\n                    string result = streamReader.ReadToEnd();\r\n\r\n                    // get the url to the repo\r\n                    string[] splitResults = result.Split(',');\r\n                    for (int i = 0; i < splitResults.Length; i++)\r\n                    {\r\n                        if (splitResults[i].Contains(\"http_url_to_repo\"))\r\n                        {\r\n\r\n                            string theUrl = splitResults[i].Replace(\"\\\"http_url_to_repo\\\":\\\"\", \"\");\r\n                            theUrl = theUrl.Replace(\"\\\"\", \"\");\r\n                            theRunners.Add(new aRunner(id, name, theUrl));\r\n\r\n                        }\r\n                    }\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not get listing of GitLab runners. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n\r\n\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n    }\r\n\r\n\r\n}"
  },
  {
    "path": "SCMKit/modules/gitlab/SnippetList.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Net;\r\nusing System.Net.Security;\r\nusing System.Security.Cryptography.X509Certificates;\r\nusing System.Threading.Tasks;\r\nusing System.IO;\r\nusing Newtonsoft.Json;\r\n\r\nnamespace SCMKit.modules.gitlab\r\n{\r\n\r\n    // custom class to handle the JSON output of snippet result\r\n    public class snippetResult\r\n    {\r\n\r\n        public string id { get; set; }\r\n        public string title { get; set; }\r\n        public string description { get; set; }\r\n        public string visibility { get; set; }\r\n        public string updatedAt { get; set; }\r\n        public string createdAt { get; set; }\r\n        public string project_id { get; set; }\r\n        public string web_url { get; set; }\r\n        public string raw_url { get; set; }\r\n        public string ssh_url_to_repo { get; set; }\r\n        public string http_url_to_repo { get; set; }\r\n        public Dictionary<string, string> author { get; set; }\r\n        public string fileName { get; set; }\r\n        public Dictionary<string, string>[] files { get; set; }\r\n\r\n        public snippetResult()\r\n        {\r\n\r\n        }\r\n\r\n    }\r\n\r\n\r\n    class SnippetList\r\n    {\r\n\r\n\r\n        public static async Task execute(string credential, string url, string options, string system)\r\n        {\r\n\r\n\r\n            // Generate module header\r\n            Console.WriteLine(library.Utils.GenerateHeader(\"listsnippet\", credential, url, options, system));\r\n\r\n\r\n            try\r\n            {\r\n                ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };\r\n                ServicePointManager.Expect100Continue = true;\r\n                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\r\n\r\n                await library.Utils.HeartbeatRequest(url);\r\n\r\n                string accessToken = \"\";\r\n\r\n\r\n                // if username/password auth being used, get the access token first. this is needed for subsequent API requests\r\n                if (credential.Contains(\":\"))\r\n                {\r\n\r\n                    accessToken = library.GitLabUtils.GetAccessToken(credential, url);\r\n\r\n                }\r\n\r\n\r\n                // create table header\r\n                string tableHeader = string.Format(\"{0,20} | {1,70}\", \"Title\", \"Raw URL\");\r\n                Console.WriteLine(tableHeader);\r\n                Console.WriteLine(new String('-', tableHeader.Length));\r\n\r\n\r\n                // get snippets for user\r\n                var webRequest = (HttpWebRequest)System.Net.WebRequest.Create(url + \"/api/v4/snippets\");\r\n                if (webRequest != null)\r\n                {\r\n                    // set header values\r\n                    webRequest.Method = \"GET\";\r\n                    webRequest.ContentType = \"application/json\";\r\n                    webRequest.UserAgent = \"SCMKIT-5dc493ada400c79dd318abbe770dac7c\";\r\n\r\n                    // if we need to pass the token obtained from the username/password auth\r\n                    if (credential.Contains(\":\"))\r\n                    {\r\n                        webRequest.Headers.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n                    }\r\n                    // if user just specified personal access token\r\n                    else\r\n                    {\r\n                        webRequest.Headers.Add(\"PRIVATE-TOKEN\", credential);\r\n                    }\r\n\r\n                    // get web response\r\n                    WebResponse myWebResponse = await webRequest.GetResponseAsync();\r\n                    string content;\r\n                    var reader = new StreamReader(myWebResponse.GetResponseStream());\r\n                    content = reader.ReadToEnd();\r\n\r\n                    // parse the JSON output and display results\r\n                    List<snippetResult> snippetResults = JsonConvert.DeserializeObject<List<snippetResult>>(content);\r\n                    foreach (snippetResult item in snippetResults)\r\n                    {\r\n\r\n                        Console.WriteLine(\"{0,20} | {1,70}\", item.title, item.raw_url);\r\n\r\n                    }\r\n\r\n                }\r\n\r\n\r\n            }\r\n\r\n            catch (Exception ex)\r\n            {\r\n                Console.WriteLine(\"\");\r\n                Console.WriteLine(\"[-] ERROR: Could not retrieve listing of snippets for current user. Exception: \" + ex.ToString());\r\n                Console.WriteLine(\"\");\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n    }\r\n\r\n}"
  },
  {
    "path": "SCMKit/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<packages>\r\n  <package id=\"Costura.Fody\" version=\"3.3.3\" targetFramework=\"net48\" />\r\n  <package id=\"Fody\" version=\"4.0.2\" targetFramework=\"net48\" developmentDependency=\"true\" />\r\n  <package id=\"GitLabApiClient\" version=\"1.8.0\" targetFramework=\"net48\" />\r\n  <package id=\"Newtonsoft.Json\" version=\"13.0.1\" targetFramework=\"net48\" />\r\n  <package id=\"Octokit\" version=\"2.0.1\" targetFramework=\"net48\" />\r\n</packages>"
  },
  {
    "path": "SCMKit.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.31727.386\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"SCMKit\", \"SCMKit\\SCMKit.csproj\", \"{266C644A-69B1-426B-A47C-1CF32B211F80}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{266C644A-69B1-426B-A47C-1CF32B211F80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{266C644A-69B1-426B-A47C-1CF32B211F80}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{266C644A-69B1-426B-A47C-1CF32B211F80}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{266C644A-69B1-426B-A47C-1CF32B211F80}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {F7FA0DD4-D75B-4F67-91D1-A7019B776721}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  }
]