├── .editorconfig
├── .gitattributes
├── .github
├── dependabot.yml
├── release.yml
└── workflows
│ ├── build.yml
│ ├── changelog.config
│ ├── changelog.yml
│ ├── dotnet-file.yml
│ ├── includes.yml
│ ├── os-matrix.json
│ ├── pages.yml
│ └── triage.yml
├── .gitignore
├── .netconfig
├── CredentialManager.sln
├── Directory.Build.rsp
├── Directory.Solution.targets
├── Gemfile
├── _config.yml
├── assets
├── css
│ └── style.scss
└── images
│ ├── gcm.png
│ └── gcm.svg
├── changelog.md
├── license.txt
├── readme.md
└── src
├── Analyzers
├── Analyzers.csproj
└── Devlooped.CredentialManager.targets
├── Core
├── .editorconfig
├── AssemblyUtils.cs
├── Authentication
│ └── OAuth
│ │ ├── HttpListenerExtensions.cs
│ │ ├── IOAuth2WebBrowser.cs
│ │ ├── Json
│ │ ├── DeviceAuthorizationEndpointResponseJson.cs
│ │ ├── ErrorResponseJson.cs
│ │ └── TokenEndpointResponseJson.cs
│ │ ├── OAuth2AuthorizationCodeResult.cs
│ │ ├── OAuth2Client.cs
│ │ ├── OAuth2Constants.cs
│ │ ├── OAuth2CryptographicGenerator.cs
│ │ ├── OAuth2DeviceCodeResult.cs
│ │ ├── OAuth2Exception.cs
│ │ ├── OAuth2ServerEndpoints.cs
│ │ ├── OAuth2SystemWebBrowser.cs
│ │ └── OAuth2TokenResult.cs
├── Base64UrlConvert.cs
├── BrowserUtils.cs
├── ChildProcess.cs
├── CommandContext.cs
├── Constants.cs
├── ConvertUtils.cs
├── Core.csproj
├── Credential.cs
├── CredentialCacheStore.cs
├── CredentialStore.cs
├── CurlCookie.cs
├── DictionaryExtensions.cs
├── DisposableObject.cs
├── EncodingEx.cs
├── EnsureArgument.cs
├── EnvironmentBase.cs
├── FileCredential.cs
├── FileSystem.cs
├── Git.cs
├── GitConfiguration.cs
├── GitConfigurationEntry.cs
├── GitConfigurationKeyComparer.cs
├── GitStreamReader.cs
├── GitVersion.cs
├── Gpg.cs
├── HttpClientFactory.cs
├── HttpRequestExtensions.cs
├── ICredentialStore.cs
├── ISessionManager.cs
├── ISystemPrompts.cs
├── ITerminal.cs
├── ITrace2Writer.cs
├── IniFile.cs
├── Interop
│ ├── InteropException.cs
│ ├── InteropUtils.cs
│ ├── Linux
│ │ ├── LinuxFileSystem.cs
│ │ ├── LinuxSessionManager.cs
│ │ ├── LinuxTerminal.cs
│ │ ├── Native
│ │ │ ├── Glib.cs
│ │ │ ├── Gobject.cs
│ │ │ ├── Libsecret.cs
│ │ │ └── termios_Linux.cs
│ │ ├── SecretServiceCollection.cs
│ │ └── SecretServiceCredential.cs
│ ├── MacOS
│ │ ├── MacOSEnvironment.cs
│ │ ├── MacOSFileSystem.cs
│ │ ├── MacOSKeychain.cs
│ │ ├── MacOSKeychainCredential.cs
│ │ ├── MacOSSessionManager.cs
│ │ ├── MacOSTerminal.cs
│ │ └── Native
│ │ │ ├── CoreFoundation.cs
│ │ │ ├── LibC.cs
│ │ │ ├── LibSystem.cs
│ │ │ ├── SecurityFramework.cs
│ │ │ └── termios_MacOS.cs
│ ├── Posix
│ │ ├── GpgPassCredentialStore.cs
│ │ ├── Native
│ │ │ ├── Fcntl.cs
│ │ │ ├── Signal.cs
│ │ │ ├── Stat.cs
│ │ │ ├── Stdio.cs
│ │ │ ├── Stdlib.cs
│ │ │ ├── Termios.cs
│ │ │ └── Unistd.cs
│ │ ├── PosixEnvironment.cs
│ │ ├── PosixFileDescriptor.cs
│ │ ├── PosixFileSystem.Custom.cs
│ │ ├── PosixFileSystem.cs
│ │ ├── PosixSessionManager.cs
│ │ └── PosixTerminal.cs
│ ├── U8StringConverter.cs
│ ├── U8StringMarshaler.cs
│ └── Windows
│ │ ├── DpapiCredentialStore.cs
│ │ ├── Native
│ │ ├── Advapi32.cs
│ │ ├── CredUi.cs
│ │ ├── Kernel32.cs
│ │ ├── Ole32.cs
│ │ ├── Shell32.cs
│ │ ├── User32.cs
│ │ └── Win32Error.cs
│ │ ├── WindowsCredential.cs
│ │ ├── WindowsCredentialManager.cs
│ │ ├── WindowsEnvironment.cs
│ │ ├── WindowsFileSystem.cs
│ │ ├── WindowsProcessManager.cs
│ │ ├── WindowsSessionManager.cs
│ │ ├── WindowsSettings.cs
│ │ ├── WindowsSystemPrompts.cs
│ │ └── WindowsTerminal.cs
├── NameValueCollectionExtensions.cs
├── NullCredentialStore.cs
├── PlaintextCredentialStore.cs
├── PlatformUtils.cs
├── ProcessManager.cs
├── Settings.cs
├── StandardStreams.cs
├── StreamExtensions.cs
├── StringExtensions.cs
├── Trace.cs
├── Trace2.cs
├── Trace2CollectorWriter.cs
├── Trace2Exception.cs
├── Trace2FileWriter.cs
├── Trace2Message.cs
├── Trace2StreamWriter.cs
├── TraceUtils.cs
├── UriExtensions.cs
└── WslUtils.cs
├── CredentialManager
├── CredentialManager.cs
├── CredentialManager.csproj
├── exclude.txt
└── readme.md
├── Directory.Build.props
├── Directory.Build.targets
├── Directory.props
├── Directory.targets
├── SponsorLink
├── Analyzer
│ ├── Analyzer.csproj
│ ├── GraceApiAnalyzer.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── StatusReportingAnalyzer.cs
│ ├── StatusReportingGenerator.cs
│ └── buildTransitive
│ │ └── SponsorableLib.targets
├── Directory.Build.props
├── Directory.Build.targets
├── Library
│ ├── Library.csproj
│ ├── MyClass.cs
│ ├── Resources.resx
│ └── readme.md
├── SponsorLink.Analyzer.Tests.targets
├── SponsorLink.Analyzer.targets
├── SponsorLink
│ ├── AnalyzerOptionsExtensions.cs
│ ├── AppDomainDictionary.cs
│ ├── DiagnosticsManager.cs
│ ├── ManifestStatus.cs
│ ├── Resources.es-AR.resx
│ ├── Resources.es.resx
│ ├── Resources.resx
│ ├── SponsorLink.cs
│ ├── SponsorLink.csproj
│ ├── SponsorLinkAnalyzer.cs
│ ├── SponsorStatus.cs
│ ├── SponsorableLib.targets
│ ├── Tracing.cs
│ ├── buildTransitive
│ │ └── Devlooped.Sponsors.targets
│ └── sponsorable.md
├── SponsorLinkAnalyzer.sln
├── Tests
│ ├── .netconfig
│ ├── AnalyzerTests.cs
│ ├── Attributes.cs
│ ├── Extensions.cs
│ ├── JsonOptions.cs
│ ├── Resources.resx
│ ├── Sample.cs
│ ├── SponsorLinkTests.cs
│ ├── SponsorableManifest.cs
│ ├── Tests.csproj
│ └── keys
│ │ ├── kzu.key
│ │ ├── kzu.key.jwk
│ │ ├── kzu.key.txt
│ │ ├── kzu.pub
│ │ ├── kzu.pub.jwk
│ │ ├── kzu.pub.txt
│ │ └── sponsorlink.jwt
├── jwk.ps1
└── readme.md
├── Tests
├── Attributes.cs
├── EndToEnd.cs
└── Tests.csproj
└── icon.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | # normalize by default
2 | * text=auto encoding=UTF-8
3 | *.sh text eol=lf
4 |
5 | # These are windows specific files which we may as well ensure are
6 | # always crlf on checkout
7 | *.bat text eol=crlf
8 | *.cmd text eol=crlf
9 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Please see the documentation for all configuration options:
2 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
3 |
4 | version: 2
5 | updates:
6 | - package-ecosystem: nuget
7 | directory: /
8 | schedule:
9 | interval: daily
10 | groups:
11 | Azure:
12 | patterns:
13 | - "Azure*"
14 | - "Microsoft.Azure*"
15 | Identity:
16 | patterns:
17 | - "System.IdentityModel*"
18 | - "Microsoft.IdentityModel*"
19 | System:
20 | patterns:
21 | - "System*"
22 | exclude-patterns:
23 | - "System.IdentityModel*"
24 | Extensions:
25 | patterns:
26 | - "Microsoft.Extensions*"
27 | Web:
28 | patterns:
29 | - "Microsoft.AspNetCore*"
30 | Tests:
31 | patterns:
32 | - "Microsoft.NET.Test*"
33 | - "xunit*"
34 | - "coverlet*"
35 | ThisAssembly:
36 | patterns:
37 | - "ThisAssembly*"
38 | ProtoBuf:
39 | patterns:
40 | - "protobuf-*"
41 |
--------------------------------------------------------------------------------
/.github/release.yml:
--------------------------------------------------------------------------------
1 | changelog:
2 | exclude:
3 | labels:
4 | - bydesign
5 | - dependencies
6 | - duplicate
7 | - question
8 | - invalid
9 | - wontfix
10 | - need info
11 | - techdebt
12 | authors:
13 | - devlooped-bot
14 | - dependabot
15 | - github-actions
16 | categories:
17 | - title: ✨ Implemented enhancements
18 | labels:
19 | - enhancement
20 | - title: 🐛 Fixed bugs
21 | labels:
22 | - bug
23 | - title: 📝 Documentation updates
24 | labels:
25 | - docs
26 | - documentation
27 | - title: 🔨 Other
28 | labels:
29 | - '*'
30 | exclude:
31 | labels:
32 | - dependencies
33 |
--------------------------------------------------------------------------------
/.github/workflows/changelog.config:
--------------------------------------------------------------------------------
1 | usernames-as-github-logins=true
2 | issues_wo_labels=true
3 | pr_wo_labels=true
4 | exclude-labels=bydesign,dependencies,duplicate,discussion,question,invalid,wontfix,need info,docs
5 | enhancement-label=:sparkles: Implemented enhancements:
6 | bugs-label=:bug: Fixed bugs:
7 | issues-label=:hammer: Other:
8 | pr-label=:twisted_rightwards_arrows: Merged:
9 | unreleased=false
10 |
--------------------------------------------------------------------------------
/.github/workflows/changelog.yml:
--------------------------------------------------------------------------------
1 | name: changelog
2 | on:
3 | workflow_dispatch:
4 | release:
5 | types: [released]
6 |
7 | jobs:
8 | changelog:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: 🤖 defaults
12 | uses: devlooped/actions-bot@v1
13 | with:
14 | name: ${{ secrets.BOT_NAME }}
15 | email: ${{ secrets.BOT_EMAIL }}
16 | gh_token: ${{ secrets.GH_TOKEN }}
17 | github_token: ${{ secrets.GITHUB_TOKEN }}
18 |
19 | - name: 🤘 checkout
20 | uses: actions/checkout@v4
21 | with:
22 | fetch-depth: 0
23 | ref: main
24 | token: ${{ env.GH_TOKEN }}
25 |
26 | - name: ⚙ ruby
27 | uses: ruby/setup-ruby@v1
28 | with:
29 | ruby-version: 3.0.3
30 |
31 | - name: ⚙ changelog
32 | run: |
33 | gem install github_changelog_generator
34 | github_changelog_generator --user ${GITHUB_REPOSITORY%/*} --project ${GITHUB_REPOSITORY##*/} --token $GH_TOKEN --o changelog.md --config-file .github/workflows/changelog.config
35 |
36 | - name: 🚀 changelog
37 | run: |
38 | git add changelog.md
39 | (git commit -m "🖉 Update changelog with ${GITHUB_REF#refs/*/}" && git push) || echo "Done"
--------------------------------------------------------------------------------
/.github/workflows/dotnet-file.yml:
--------------------------------------------------------------------------------
1 | # Synchronizes .netconfig-configured files with dotnet-file
2 | name: dotnet-file
3 | on:
4 | workflow_dispatch:
5 | schedule:
6 | - cron: "0 0 * * *"
7 | push:
8 | branches: [ 'dotnet-file' ]
9 |
10 | env:
11 | DOTNET_NOLOGO: true
12 |
13 | jobs:
14 | run:
15 | uses: devlooped/oss/.github/workflows/dotnet-file-core.yml@main
16 | secrets: inherit
--------------------------------------------------------------------------------
/.github/workflows/includes.yml:
--------------------------------------------------------------------------------
1 | name: +Mᐁ includes
2 | on:
3 | workflow_dispatch:
4 | push:
5 | branches:
6 | - 'main'
7 | paths:
8 | - '**.md'
9 | - '!changelog.md'
10 |
11 | jobs:
12 | includes:
13 | runs-on: ubuntu-latest
14 | permissions:
15 | contents: write
16 | pull-requests: write
17 | steps:
18 | - name: 🤖 defaults
19 | uses: devlooped/actions-bot@v1
20 | with:
21 | name: ${{ secrets.BOT_NAME }}
22 | email: ${{ secrets.BOT_EMAIL }}
23 | gh_token: ${{ secrets.GH_TOKEN }}
24 | github_token: ${{ secrets.GITHUB_TOKEN }}
25 |
26 | - name: 🤘 checkout
27 | uses: actions/checkout@v4
28 | with:
29 | token: ${{ env.GH_TOKEN }}
30 |
31 | - name: +Mᐁ includes
32 | uses: devlooped/actions-includes@v1
33 |
34 | - name: ✍ pull request
35 | uses: peter-evans/create-pull-request@v6
36 | with:
37 | add-paths: '**.md'
38 | base: main
39 | branch: markdown-includes
40 | delete-branch: true
41 | labels: docs
42 | author: ${{ env.BOT_AUTHOR }}
43 | committer: ${{ env.BOT_AUTHOR }}
44 | commit-message: +Mᐁ includes
45 | title: +Mᐁ includes
46 | body: +Mᐁ includes
47 | token: ${{ env.GH_TOKEN }}
48 |
--------------------------------------------------------------------------------
/.github/workflows/os-matrix.json:
--------------------------------------------------------------------------------
1 | [ 'ubuntu-latest', 'windows-latest', 'macOS-latest' ]
--------------------------------------------------------------------------------
/.github/workflows/pages.yml:
--------------------------------------------------------------------------------
1 | # Workflow to cross-post a jekyll site (or GitHub Pages)
2 | # to another org/repo.
3 | # Required secrets in repository consuming this workflow:
4 | # - PAGES_ORGANIZATION: the target organization to publish
5 | # pages to.
6 | # - PAGES_ACCESS_TOKEN: a token that is valid in the target
7 | # org/repo for pushing the resulting site
8 | # - PAGES_REPOSITORY: optional repository name under the
9 | # target organization. Defaults to source repo name.
10 |
11 | name: pages
12 | on:
13 | workflow_dispatch:
14 | push:
15 | branches:
16 | - main
17 | - pages
18 | - docs
19 |
20 | env:
21 | PAGES_ORGANIZATION: ${{ secrets.PAGES_ORGANIZATION }}
22 | PAGES_REPOSITORY: ${{ secrets.PAGES_REPOSITORY }}
23 |
24 | jobs:
25 | gh-pages:
26 | runs-on: ubuntu-latest
27 | env:
28 | PAGES_ORGANIZATION: ${{ secrets.PAGES_ORGANIZATION }}
29 | PAGES_REPOSITORY: ${{ secrets.PAGES_REPOSITORY }}
30 | PAGES_ACCESS_TOKEN: ${{ secrets.PAGES_ACCESS_TOKEN }}
31 | steps:
32 | - name: ✅ organization
33 | if: env.PAGES_ORGANIZATION == ''
34 | run: |
35 | echo "::error title=PAGES_ORGANIZATION secret is required."
36 | exit 1
37 |
38 | - name: ✅ token
39 | if: env.PAGES_ACCESS_TOKEN == ''
40 | run: |
41 | echo "::error title=PAGES_ACCESS_TOKEN secret is required."
42 | exit 1
43 |
44 | - name: 🤘 checkout
45 | uses: actions/checkout@v2
46 |
47 | - name: ⚙ jekyll
48 | run: |
49 | sudo gem install bundler
50 | sudo bundle install
51 |
52 | - name: 🖉 default repo
53 | if: env.PAGES_REPOSITORY == ''
54 | run: echo "PAGES_REPOSITORY=${GITHUB_REPOSITORY#*/}" >> $GITHUB_ENV
55 |
56 | - name: 🙏 build
57 | run: bundle exec jekyll build -b ${{ env.PAGES_REPOSITORY }}
58 | env:
59 | JEKYLL_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
60 |
61 | - name: ✓ commit
62 | run: |
63 | cd _site
64 | git init
65 | git add -A
66 | git config --local user.email "bot@clarius.org"
67 | git config --local user.name "bot@clarius.org"
68 | git commit -m "Publish pages from ${GITHUB_REPOSITORY}@${GITHUB_SHA:0:9}"
69 |
70 | - name: 🚀 push
71 | uses: ad-m/github-push-action@v0.6.0
72 | with:
73 | github_token: ${{ env.PAGES_ACCESS_TOKEN }}
74 | repository: ${{ env.PAGES_ORGANIZATION }}/${{ env.PAGES_REPOSITORY }}
75 | branch: gh-pages
76 | force: true
77 | directory: ./_site
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | obj
3 | artifacts
4 | pack
5 | TestResults
6 | results
7 | BenchmarkDotNet.Artifacts
8 | /app
9 | .vs
10 | .vscode
11 | .genaiscript
12 | .idea
13 | local.settings.json
14 |
15 | *.suo
16 | *.sdf
17 | *.userprefs
18 | *.user
19 | *.nupkg
20 | *.metaproj
21 | *.tmp
22 | *.log
23 | *.cache
24 | *.binlog
25 | *.zip
26 | __azurite*.*
27 | __*__
28 |
29 | .nuget
30 | *.lock.json
31 | *.nuget.props
32 | *.nuget.targets
33 |
34 | node_modules
35 | _site
36 | .jekyll-metadata
37 | .jekyll-cache
38 | .sass-cache
39 | Gemfile.lock
40 | package-lock.json
41 |
--------------------------------------------------------------------------------
/CredentialManager.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.32421.90
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CredentialManager", "src\CredentialManager\CredentialManager.csproj", "{141A5D74-1821-41CB-831A-0CDCD469E4AE}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Analyzers", "src\Analyzers\Analyzers.csproj", "{47DE5EE9-22A7-4D23-A50E-0724A900D290}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\Core.csproj", "{D0CE060F-5C92-494F-A4D4-441F7CDB1340}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "src\Tests\Tests.csproj", "{160A2CD4-2C93-4C6E-BD87-5F462A932C58}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {141A5D74-1821-41CB-831A-0CDCD469E4AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {141A5D74-1821-41CB-831A-0CDCD469E4AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {141A5D74-1821-41CB-831A-0CDCD469E4AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {141A5D74-1821-41CB-831A-0CDCD469E4AE}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {47DE5EE9-22A7-4D23-A50E-0724A900D290}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {47DE5EE9-22A7-4D23-A50E-0724A900D290}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {47DE5EE9-22A7-4D23-A50E-0724A900D290}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {47DE5EE9-22A7-4D23-A50E-0724A900D290}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {D0CE060F-5C92-494F-A4D4-441F7CDB1340}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {D0CE060F-5C92-494F-A4D4-441F7CDB1340}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {D0CE060F-5C92-494F-A4D4-441F7CDB1340}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {D0CE060F-5C92-494F-A4D4-441F7CDB1340}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {160A2CD4-2C93-4C6E-BD87-5F462A932C58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {160A2CD4-2C93-4C6E-BD87-5F462A932C58}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {160A2CD4-2C93-4C6E-BD87-5F462A932C58}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {160A2CD4-2C93-4C6E-BD87-5F462A932C58}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {9553CCFA-953D-400C-BE44-25CA2B8E0F31}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/Directory.Build.rsp:
--------------------------------------------------------------------------------
1 | # See https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-response-files
2 | -nr:false
3 | -m:1
4 | -v:m
5 | -clp:Summary;ForceNoAlign
6 |
--------------------------------------------------------------------------------
/Directory.Solution.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 | $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\src\NuGetize.targets))
4 | windows
5 | osx
6 | linux
7 |
8 |
9 |
10 |
11 |
12 | CustomAfterMicrosoftCommonTargets=$(CustomAfterMicrosoftCommonTargets);
13 | OSPlatform=$(OSPlatform);
14 | %(AdditionalProperties)
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'github-pages', '~> 231', group: :jekyll_plugins
4 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-slate
2 |
3 | exclude: [ 'src/', '*.sln', 'Gemfile*', '*.rsp' ]
--------------------------------------------------------------------------------
/assets/css/style.scss:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | @import "jekyll-theme-slate";
5 |
6 | .inner {
7 | max-width: 960px;
8 | }
9 |
10 | pre, code {
11 | background-color: unset;
12 | font-size: unset;
13 | }
14 |
15 | code {
16 | font-size: 0.80em;
17 | }
18 |
19 | h1 > img {
20 | border: unset;
21 | box-shadow: unset;
22 | vertical-align: middle;
23 | -moz-box-shadow: unset;
24 | -o-box-shadow: unset;
25 | -ms-box-shadow: unset;
26 | }
27 |
--------------------------------------------------------------------------------
/assets/images/gcm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devlooped/CredentialManager/752b34b21d807de3348b16d2be507a5f7e8213b9/assets/images/gcm.png
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Daniel Cazzulino and Contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/src/Analyzers/Analyzers.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Devlooped.CredentialManager
5 | Devlooped.CredentialManager.Analyzers
6 | netstandard2.0
7 | analyzers/dotnet
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | $(MSBuildThisFileDirectory)..\SponsorLink\SponsorLink.Analyzer.targets
24 |
25 | Devlooped.CredentialManager
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/Analyzers/Devlooped.CredentialManager.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Core/.editorconfig:
--------------------------------------------------------------------------------
1 | [**]
2 | generated_code = true
--------------------------------------------------------------------------------
/src/Core/AssemblyUtils.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | namespace GitCredentialManager;
4 |
5 | public static class AssemblyUtils
6 | {
7 | public static bool TryGetAssemblyVersion(out string version)
8 | {
9 | try
10 | {
11 | var assembly = Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly();
12 | var assemblyVersionAttribute = assembly.GetCustomAttribute();
13 | version = assemblyVersionAttribute is null
14 | ? assembly.GetName().Version.ToString()
15 | : assemblyVersionAttribute.InformationalVersion;
16 | return true;
17 | }
18 | catch
19 | {
20 | version = null;
21 | return false;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Core/Authentication/OAuth/HttpListenerExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Text;
3 | using System.Threading.Tasks;
4 |
5 | namespace GitCredentialManager.Authentication.OAuth
6 | {
7 | public static class HttpListenerExtensions
8 | {
9 | public static async Task WriteResponseAsync(this HttpListenerResponse response, string responseText)
10 | {
11 | byte[] responseData = Encoding.UTF8.GetBytes(responseText);
12 | response.ContentLength64 = responseData.Length;
13 | await response.OutputStream.WriteAsync(responseData, 0, responseData.Length);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Core/Authentication/OAuth/IOAuth2WebBrowser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace GitCredentialManager.Authentication.OAuth
7 | {
8 | public interface IOAuth2WebBrowser
9 | {
10 | Uri UpdateRedirectUri(Uri uri);
11 |
12 | Task GetAuthenticationCodeAsync(Uri authorizationUri, Uri redirectUri, CancellationToken ct);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Core/Authentication/OAuth/Json/DeviceAuthorizationEndpointResponseJson.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text.Json.Serialization;
3 |
4 | namespace GitCredentialManager.Authentication.OAuth.Json
5 | {
6 | public class DeviceAuthorizationEndpointResponseJson
7 | {
8 | [JsonRequired]
9 | [JsonPropertyName("device_code")]
10 | public string DeviceCode { get; set; }
11 |
12 | [JsonRequired]
13 | [JsonPropertyName("user_code")]
14 | public string UserCode { get; set; }
15 |
16 | [JsonRequired]
17 | [JsonPropertyName("verification_uri")]
18 | public Uri VerificationUri { get; set; }
19 |
20 | [JsonPropertyName("expires_in")]
21 | public long ExpiresIn { get; set; }
22 |
23 | [JsonPropertyName("interval")]
24 | public long PollingInterval { get; set; }
25 |
26 | public OAuth2DeviceCodeResult ToResult()
27 | {
28 | return new OAuth2DeviceCodeResult(DeviceCode, UserCode, VerificationUri, TimeSpan.FromSeconds(PollingInterval))
29 | {
30 | ExpiresIn = TimeSpan.FromSeconds(ExpiresIn)
31 | };
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Core/Authentication/OAuth/Json/ErrorResponseJson.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Text.Json;
4 | using System.Text.Json.Serialization;
5 |
6 | namespace GitCredentialManager.Authentication.OAuth.Json
7 | {
8 | public class ErrorResponseJson
9 | {
10 | [JsonRequired]
11 | [JsonPropertyName("error")]
12 | public string Error { get; set; }
13 |
14 | [JsonPropertyName("error_description")]
15 | public string Description { get; set; }
16 |
17 | [JsonPropertyName("error_uri")]
18 | public Uri Uri { get; set; }
19 |
20 | public OAuth2Exception ToException(Exception innerException = null)
21 | {
22 | var message = new StringBuilder(Error);
23 |
24 | if (!string.IsNullOrEmpty(Description))
25 | {
26 | message.AppendFormat(": {0}", Description);
27 | }
28 |
29 | if (Uri != null)
30 | {
31 | message.AppendFormat(" [{0}]", Uri);
32 | }
33 |
34 | return new OAuth2Exception(message.ToString(), innerException) {HelpLink = Uri?.ToString()};
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Core/Authentication/OAuth/Json/TokenEndpointResponseJson.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text.Json;
3 | using System.Text.Json.Serialization;
4 |
5 | namespace GitCredentialManager.Authentication.OAuth.Json
6 | {
7 | public class TokenEndpointResponseJson
8 | {
9 | [JsonRequired]
10 | [JsonPropertyName("access_token")]
11 | public string AccessToken { get; set; }
12 |
13 | [JsonRequired]
14 | [JsonPropertyName("token_type")]
15 | public string TokenType { get; set; }
16 |
17 | [JsonPropertyName("expires_in")]
18 | public long? ExpiresIn { get; set; }
19 |
20 | [JsonPropertyName("refresh_token")]
21 | public string RefreshToken { get; set; }
22 |
23 | [JsonPropertyName("scope")]
24 | public virtual string Scope { get; set; }
25 |
26 | public OAuth2TokenResult ToResult()
27 | {
28 | return new OAuth2TokenResult(AccessToken, TokenType)
29 | {
30 | ExpiresIn = ExpiresIn.HasValue ? TimeSpan.FromSeconds(ExpiresIn.Value) : null,
31 | RefreshToken = RefreshToken,
32 | Scopes = Scope?.Split(' ')
33 | };
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Core/Authentication/OAuth/OAuth2AuthorizationCodeResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace GitCredentialManager.Authentication.OAuth
4 | {
5 | public class OAuth2AuthorizationCodeResult
6 | {
7 | public OAuth2AuthorizationCodeResult(string code, Uri redirectUri = null, string codeVerifier = null)
8 | {
9 | Code = code;
10 | RedirectUri = redirectUri;
11 | CodeVerifier = codeVerifier;
12 | }
13 |
14 | public string Code { get; }
15 | public Uri RedirectUri { get; }
16 | public string CodeVerifier { get; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Core/Authentication/OAuth/OAuth2Constants.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GitCredentialManager.Authentication.OAuth
3 | {
4 | public static class OAuth2Constants
5 | {
6 | public const string ClientIdParameter = "client_id";
7 | public const string ClientSecretParameter = "client_secret";
8 | public const string RedirectUriParameter = "redirect_uri";
9 | public const string ScopeParameter = "scope";
10 | public const string Trace2Category = "oauth2";
11 |
12 | public static class AuthorizationEndpoint
13 | {
14 | public const string StateParameter = "state";
15 | public const string AuthorizationCodeResponseType = "code";
16 | public const string ResponseTypeParameter = "response_type";
17 | public const string PkceChallengeParameter = "code_challenge";
18 | public const string PkceChallengeMethodParameter = "code_challenge_method";
19 | public const string PkceChallengeMethodPlain = "plain";
20 | public const string PkceChallengeMethodS256 = "S256";
21 | }
22 |
23 | public static class AuthorizationGrantResponse
24 | {
25 | public const string AuthorizationCodeParameter = "code";
26 | public const string ErrorCodeParameter = "error";
27 | public const string ErrorDescriptionParameter = "error_description";
28 | public const string ErrorUriParameter = "error_uri";
29 | public const string StateParameter = "state";
30 | }
31 |
32 | public static class TokenEndpoint
33 | {
34 | public const string GrantTypeParameter = "grant_type";
35 | public const string AuthorizationCodeGrantType = "authorization_code";
36 | public const string RefreshTokenGrantType = "refresh_token";
37 | public const string PkceVerifierParameter = "code_verifier";
38 | public const string AuthorizationCodeParameter = "code";
39 | public const string RefreshTokenParameter = "refresh_token";
40 | }
41 |
42 | public static class DeviceAuthorization
43 | {
44 | public const string GrantTypeParameter = "grant_type";
45 | public const string DeviceCodeParameter = "device_code";
46 | public const string DeviceCodeGrantType = "urn:ietf:params:oauth:grant-type:device_code";
47 |
48 | public static class Errors
49 | {
50 | public const string AuthorizationPending = "authorization_pending";
51 | public const string SlowDown = "slow_down";
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Core/Authentication/OAuth/OAuth2DeviceCodeResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace GitCredentialManager.Authentication.OAuth
4 | {
5 | public class OAuth2DeviceCodeResult
6 | {
7 | public OAuth2DeviceCodeResult(string deviceCode, string userCode, Uri verificationUri, TimeSpan? interval)
8 | {
9 | DeviceCode = deviceCode;
10 | UserCode = userCode;
11 | VerificationUri = verificationUri;
12 | PollingInterval = interval ?? TimeSpan.FromSeconds(5);
13 | }
14 |
15 | public string DeviceCode { get; }
16 |
17 | public string UserCode { get; }
18 |
19 | public Uri VerificationUri { get; }
20 |
21 | public TimeSpan PollingInterval { get; }
22 |
23 | public TimeSpan? ExpiresIn { get; internal set; }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Core/Authentication/OAuth/OAuth2Exception.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace GitCredentialManager.Authentication.OAuth
4 | {
5 | public class OAuth2Exception : Exception
6 | {
7 | public OAuth2Exception(string message) : base(message) { }
8 |
9 | public OAuth2Exception(string message, Exception innerException) : base(message, innerException) { }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Core/Authentication/OAuth/OAuth2ServerEndpoints.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace GitCredentialManager.Authentication.OAuth
4 | {
5 | ///
6 | /// Represents the various OAuth2 endpoints for an .
7 | ///
8 | public class OAuth2ServerEndpoints
9 | {
10 | private Uri _deviceAuthorizationEndpoint;
11 |
12 | public OAuth2ServerEndpoints(Uri authorizationEndpoint, Uri tokenEndpoint)
13 | {
14 | EnsureArgument.AbsoluteUri(authorizationEndpoint, nameof(authorizationEndpoint));
15 | EnsureArgument.AbsoluteUri(tokenEndpoint, nameof(tokenEndpoint));
16 |
17 | AuthorizationEndpoint = authorizationEndpoint;
18 | TokenEndpoint = tokenEndpoint;
19 | }
20 |
21 | public Uri AuthorizationEndpoint { get; }
22 |
23 | public Uri TokenEndpoint { get; }
24 |
25 | public Uri DeviceAuthorizationEndpoint
26 | {
27 | get => _deviceAuthorizationEndpoint;
28 | set
29 | {
30 | if (value != null)
31 | {
32 | EnsureArgument.AbsoluteUri(value, nameof(value));
33 | }
34 |
35 | _deviceAuthorizationEndpoint = value;
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Core/Authentication/OAuth/OAuth2TokenResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace GitCredentialManager.Authentication.OAuth
4 | {
5 | public class OAuth2TokenResult
6 | {
7 | public OAuth2TokenResult(string accessToken, string tokenType)
8 | {
9 | AccessToken = accessToken;
10 | TokenType = tokenType;
11 | }
12 |
13 | public string AccessToken { get; }
14 |
15 | public string TokenType { get; }
16 |
17 | public string RefreshToken { get; set; }
18 |
19 | public TimeSpan? ExpiresIn { get; set; }
20 |
21 | public string[] Scopes { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Core/Base64UrlConvert.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace GitCredentialManager
4 | {
5 | public static class Base64UrlConvert
6 | {
7 | public static string Encode(byte[] data, bool includePadding = true)
8 | {
9 | const char base64PadCharacter = '=';
10 | const char base64Character62 = '+';
11 | const char base64Character63 = '/';
12 | const char base64UrlCharacter62 = '-';
13 | const char base64UrlCharacter63 = '_';
14 |
15 | // The base64url format is the same as regular base64 format except:
16 | // 1. character 62 is "-" (minus) not "+" (plus)
17 | // 2. character 63 is "_" (underscore) not "/" (slash)
18 | string base64Url = Convert.ToBase64String(data)
19 | .Replace(base64Character62, base64UrlCharacter62)
20 | .Replace(base64Character63, base64UrlCharacter63);
21 |
22 | return includePadding ? base64Url : base64Url.TrimEnd(base64PadCharacter);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Core/ChildProcess.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Threading.Tasks;
5 |
6 | namespace GitCredentialManager;
7 |
8 | public class ChildProcess : DisposableObject
9 | {
10 | private readonly ITrace2 _trace2;
11 |
12 | private DateTimeOffset _startTime;
13 | private DateTimeOffset _exitTime => Process.ExitTime;
14 | private ProcessStartInfo _startInfo => Process.StartInfo;
15 |
16 | private int _id => Process.Id;
17 |
18 | public ProcessStartInfo StartInfo => Process.StartInfo;
19 | public Process Process { get; }
20 | public StreamWriter StandardInput => Process.StandardInput;
21 | public StreamReader StandardOutput => Process.StandardOutput;
22 | public StreamReader StandardError => Process.StandardError;
23 | public int ExitCode => Process.ExitCode;
24 |
25 | public static ChildProcess Start(ITrace2 trace2, ProcessStartInfo startInfo, Trace2ProcessClass processClass)
26 | {
27 | var childProc = new ChildProcess(trace2, startInfo);
28 | childProc.Start(processClass);
29 | return childProc;
30 | }
31 |
32 | public ChildProcess(ITrace2 trace2, ProcessStartInfo startInfo)
33 | {
34 | _trace2 = trace2;
35 | Process = new Process() { StartInfo = startInfo };
36 | Process.Exited += ProcessOnExited;
37 | }
38 |
39 | public bool Start(Trace2ProcessClass processClass)
40 | {
41 | ThrowIfDisposed();
42 | // Record the time just before the process starts, since:
43 | // (1) There is no event related to Start as there is with Exit.
44 | // (2) Using Process.StartTime causes a race condition that leads
45 | // to an exception if the process finishes executing before the
46 | // variable is passed to Trace2.
47 | _startTime = DateTimeOffset.UtcNow;
48 | _trace2.WriteChildStart(
49 | _startTime,
50 | processClass,
51 | _startInfo.UseShellExecute,
52 | _startInfo.FileName,
53 | _startInfo.Arguments);
54 | return Process.Start();
55 | }
56 |
57 | public void WaitForExit() => Process.WaitForExit();
58 |
59 | public void Kill() => Process.Kill();
60 |
61 | protected override void ReleaseManagedResources()
62 | {
63 | Process.Exited -= ProcessOnExited;
64 | Process.Dispose();
65 | base.ReleaseUnmanagedResources();
66 | }
67 |
68 | private void ProcessOnExited(object sender, EventArgs e)
69 | {
70 | if (sender is Process)
71 | {
72 | double elapsedTime = (_exitTime - _startTime).TotalSeconds;
73 | _trace2.WriteChildExit(
74 | elapsedTime,
75 | _id,
76 | Process.ExitCode);
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/Core/ConvertUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace GitCredentialManager
4 | {
5 | public static class ConvertUtils
6 | {
7 | public static bool TryToInt32(object value, out int i)
8 | {
9 | return TryConvert(Convert.ToInt32, value, out i);
10 | }
11 |
12 | public static bool TryConvert(Func