37 changed files with 1742 additions and 0 deletions
@ -0,0 +1,109 @@
@@ -0,0 +1,109 @@
|
||||
# EditorConfig is awesome: http://EditorConfig.org |
||||
|
||||
# top-most EditorConfig file |
||||
root = true |
||||
|
||||
# Don't use tabs for indentation. |
||||
[*] |
||||
indent_style = space |
||||
# (Please don't specify an indent_size here; that has too many unintended consequences.) |
||||
|
||||
# Code files |
||||
[*.{cs,csx,vb,vbx}] |
||||
indent_size = 4 |
||||
insert_final_newline = true |
||||
charset = utf-8-bom |
||||
|
||||
# Xml project files |
||||
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] |
||||
indent_size = 2 |
||||
|
||||
# Xml config files |
||||
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] |
||||
indent_size = 2 |
||||
|
||||
# JSON files |
||||
[*.json] |
||||
indent_size = 2 |
||||
|
||||
# Dotnet code style settings: |
||||
[*.{cs,vb}] |
||||
# Sort using and Import directives with System.* appearing first |
||||
dotnet_sort_system_directives_first = true |
||||
# Avoid "this." and "Me." if not necessary |
||||
dotnet_style_qualification_for_field = false:suggestion |
||||
dotnet_style_qualification_for_property = false:suggestion |
||||
dotnet_style_qualification_for_method = false:suggestion |
||||
dotnet_style_qualification_for_event = false:suggestion |
||||
|
||||
# Use language keywords instead of framework type names for type references |
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion |
||||
dotnet_style_predefined_type_for_member_access = true:suggestion |
||||
|
||||
# Suggest more modern language features when available |
||||
dotnet_style_object_initializer = true:suggestion |
||||
dotnet_style_collection_initializer = true:suggestion |
||||
dotnet_style_coalesce_expression = true:suggestion |
||||
dotnet_style_null_propagation = true:suggestion |
||||
dotnet_style_explicit_tuple_names = true:suggestion |
||||
|
||||
# Prefix private members with underscore |
||||
dotnet_naming_rule.private_members_with_underscore.symbols = private_fields |
||||
dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore |
||||
dotnet_naming_rule.private_members_with_underscore.severity = suggestion |
||||
|
||||
dotnet_naming_symbols.private_fields.applicable_kinds = field |
||||
dotnet_naming_symbols.private_fields.applicable_accessibilities = private |
||||
|
||||
dotnet_naming_style.prefix_underscore.capitalization = camel_case |
||||
dotnet_naming_style.prefix_underscore.required_prefix = _ |
||||
|
||||
# Async methods should have "Async" suffix |
||||
dotnet_naming_rule.async_methods_end_in_async.symbols = any_async_methods |
||||
dotnet_naming_rule.async_methods_end_in_async.style = end_in_async |
||||
dotnet_naming_rule.async_methods_end_in_async.severity = suggestion |
||||
|
||||
dotnet_naming_symbols.any_async_methods.applicable_kinds = method |
||||
dotnet_naming_symbols.any_async_methods.applicable_accessibilities = * |
||||
dotnet_naming_symbols.any_async_methods.required_modifiers = async |
||||
|
||||
dotnet_naming_style.end_in_async.required_prefix = |
||||
dotnet_naming_style.end_in_async.required_suffix = Async |
||||
dotnet_naming_style.end_in_async.capitalization = pascal_case |
||||
dotnet_naming_style.end_in_async.word_separator = |
||||
|
||||
# CSharp code style settings: |
||||
[*.cs] |
||||
# Prefer "var" everywhere |
||||
csharp_style_var_for_built_in_types = true:suggestion |
||||
csharp_style_var_when_type_is_apparent = true:suggestion |
||||
csharp_style_var_elsewhere = true:suggestion |
||||
|
||||
# Prefer method-like constructs to have a expression-body |
||||
csharp_style_expression_bodied_methods = true:none |
||||
csharp_style_expression_bodied_constructors = true:none |
||||
csharp_style_expression_bodied_operators = true:none |
||||
|
||||
# Prefer property-like constructs to have an expression-body |
||||
csharp_style_expression_bodied_properties = true:none |
||||
csharp_style_expression_bodied_indexers = true:none |
||||
csharp_style_expression_bodied_accessors = true:none |
||||
|
||||
# Suggest more modern language features when available |
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion |
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion |
||||
csharp_style_inlined_variable_declaration = true:suggestion |
||||
csharp_style_throw_expression = true:suggestion |
||||
csharp_style_conditional_delegate_call = true:suggestion |
||||
|
||||
# Newline settings |
||||
csharp_new_line_before_open_brace = all |
||||
csharp_new_line_before_else = true |
||||
csharp_new_line_before_catch = true |
||||
csharp_new_line_before_finally = true |
||||
csharp_new_line_before_members_in_object_initializers = true |
||||
csharp_new_line_before_members_in_anonymous_types = true |
||||
|
||||
# All files |
||||
[*] |
||||
guidelines = 120 |
||||
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
*.sh eol=lf |
||||
.dockerignore eol=lf |
||||
dockerfile eol=lf |
||||
@ -0,0 +1,219 @@
@@ -0,0 +1,219 @@
|
||||
## Ignore Visual Studio temporary files, build results, and |
||||
## files generated by popular Visual Studio add-ons. |
||||
|
||||
# User-specific files |
||||
*.suo |
||||
*.user |
||||
*.userosscache |
||||
*.sln.docstates |
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio) |
||||
*.userprefs |
||||
|
||||
# Build results |
||||
[Dd]ebug/ |
||||
[Dd]ebugPublic/ |
||||
[Rr]elease/ |
||||
[Rr]eleases/ |
||||
x64/ |
||||
x86/ |
||||
build/ |
||||
bld/ |
||||
[Bb]in/ |
||||
[Oo]bj/ |
||||
|
||||
# Visual Studo 2015 cache/options directory |
||||
.vs/ |
||||
|
||||
# MSTest test Results |
||||
[Tt]est[Rr]esult*/ |
||||
[Bb]uild[Ll]og.* |
||||
|
||||
# NUNIT |
||||
*.VisualState.xml |
||||
TestResult.xml |
||||
|
||||
# Build Results of an ATL Project |
||||
[Dd]ebugPS/ |
||||
[Rr]eleasePS/ |
||||
dlldata.c |
||||
|
||||
*_i.c |
||||
*_p.c |
||||
*_i.h |
||||
*.ilk |
||||
*.meta |
||||
*.obj |
||||
*.pch |
||||
*.pdb |
||||
*.pgc |
||||
*.pgd |
||||
*.rsp |
||||
*.sbr |
||||
*.tlb |
||||
*.tli |
||||
*.tlh |
||||
*.tmp |
||||
*.tmp_proj |
||||
*.log |
||||
*.vspscc |
||||
*.vssscc |
||||
.builds |
||||
*.pidb |
||||
*.svclog |
||||
*.scc |
||||
|
||||
# Chutzpah Test files |
||||
_Chutzpah* |
||||
|
||||
# Visual C++ cache files |
||||
ipch/ |
||||
*.aps |
||||
*.ncb |
||||
*.opensdf |
||||
*.sdf |
||||
*.cachefile |
||||
|
||||
# Visual Studio profiler |
||||
*.psess |
||||
*.vsp |
||||
*.vspx |
||||
|
||||
# TFS 2012 Local Workspace |
||||
$tf/ |
||||
|
||||
# Guidance Automation Toolkit |
||||
*.gpState |
||||
|
||||
# ReSharper is a .NET coding add-in |
||||
_ReSharper*/ |
||||
*.[Rr]e[Ss]harper |
||||
*.DotSettings.user |
||||
|
||||
# JustCode is a .NET coding addin-in |
||||
.JustCode |
||||
|
||||
# TeamCity is a build add-in |
||||
_TeamCity* |
||||
|
||||
# DotCover is a Code Coverage Tool |
||||
*.dotCover |
||||
|
||||
# NCrunch |
||||
_NCrunch_* |
||||
.*crunch*.local.xml |
||||
|
||||
# MightyMoose |
||||
*.mm.* |
||||
AutoTest.Net/ |
||||
|
||||
# Web workbench (sass) |
||||
.sass-cache/ |
||||
|
||||
# Installshield output folder |
||||
[Ee]xpress/ |
||||
|
||||
# DocProject is a documentation generator add-in |
||||
DocProject/buildhelp/ |
||||
DocProject/Help/*.HxT |
||||
DocProject/Help/*.HxC |
||||
DocProject/Help/*.hhc |
||||
DocProject/Help/*.hhk |
||||
DocProject/Help/*.hhp |
||||
DocProject/Help/Html2 |
||||
DocProject/Help/html |
||||
|
||||
# Click-Once directory |
||||
publish/ |
||||
|
||||
# Publish Web Output |
||||
*.[Pp]ublish.xml |
||||
*.azurePubxml |
||||
# TODO: Comment the next line if you want to checkin your web deploy settings |
||||
# but database connection strings (with potential passwords) will be unencrypted |
||||
*.pubxml |
||||
*.publishproj |
||||
PublishProfiles/ |
||||
|
||||
# NuGet Packages |
||||
*.nupkg |
||||
# The packages folder can be ignored because of Package Restore |
||||
**/packages/* |
||||
# except build/, which is used as an MSBuild target. |
||||
!**/packages/build/ |
||||
# Uncomment if necessary however generally it will be regenerated when needed |
||||
#!**/packages/repositories.config |
||||
|
||||
# Windows Azure Build Output |
||||
csx/ |
||||
*.build.csdef |
||||
|
||||
# Windows Store app package directory |
||||
AppPackages/ |
||||
|
||||
# Others |
||||
*.[Cc]ache |
||||
ClientBin/ |
||||
[Ss]tyle[Cc]op.* |
||||
~$* |
||||
*~ |
||||
*.dbmdl |
||||
*.dbproj.schemaview |
||||
*.pfx |
||||
*.publishsettings |
||||
node_modules/ |
||||
bower_components/ |
||||
|
||||
# RIA/Silverlight projects |
||||
Generated_Code/ |
||||
|
||||
# Backup & report files from converting an old project file |
||||
# to a newer Visual Studio version. Backup files are not needed, |
||||
# because we have git ;-) |
||||
_UpgradeReport_Files/ |
||||
Backup*/ |
||||
UpgradeLog*.XML |
||||
UpgradeLog*.htm |
||||
|
||||
# SQL Server files |
||||
*.mdf |
||||
*.ldf |
||||
|
||||
# Business Intelligence projects |
||||
*.rdl.data |
||||
*.bim.layout |
||||
*.bim_*.settings |
||||
|
||||
# Microsoft Fakes |
||||
FakesAssemblies/ |
||||
|
||||
# Node.js Tools for Visual Studio |
||||
.ntvs_analysis.dat |
||||
|
||||
# Visual Studio 6 build log |
||||
*.plg |
||||
|
||||
# Visual Studio 6 workspace options file |
||||
*.opt |
||||
|
||||
# Other |
||||
project.lock.json |
||||
*.jfm |
||||
mail_dist/ |
||||
*.refactorlog |
||||
*.scmp |
||||
src/Core/Properties/launchSettings.json |
||||
*.override.env |
||||
**/*.DS_Store |
||||
src/Admin/wwwroot/lib |
||||
src/Admin/wwwroot/css |
||||
.vscode/* |
||||
**/.vscode/* |
||||
bitwarden_license/src/Portal/wwwroot/lib |
||||
bitwarden_license/src/Portal/wwwroot/css |
||||
bitwarden_license/src/Sso/wwwroot/lib |
||||
bitwarden_license/src/Sso/wwwroot/css |
||||
.github/test/build.secrets |
||||
**/CoverageOutput/ |
||||
.idea/* |
||||
**/**.swp |
||||
@ -0,0 +1,182 @@
@@ -0,0 +1,182 @@
|
||||
BITWARDEN LICENSE AGREEMENT |
||||
Version 1, 4 September 2020 |
||||
|
||||
PLEASE CAREFULLY READ THIS BITWARDEN LICENSE AGREEMENT ("AGREEMENT"). THIS |
||||
AGREEMENT CONSTITUTES A LEGALLY BINDING AGREEMENT BETWEEN YOU AND BITWARDEN, |
||||
INC. ("BITWARDEN") AND GOVERNS YOUR USE OF THE COMMERCIAL MODULES (DEFINED |
||||
BELOW). BY COPYING OR USING THE COMMERCIAL MODULES, YOU AGREE TO THIS AGREEMENT. |
||||
IF YOU DO NOT AGREE WITH THIS AGREEMENT, YOU MAY NOT COPY OR USE THE COMMERCIAL |
||||
MODULES. IF YOU ARE COPYING OR USING THE COMMERCIAL MODULES ON BEHALF OF A LEGAL |
||||
ENTITY, YOU REPRESENT AND WARRANT THAT YOU HAVE AUTHORITY TO AGREE TO THIS |
||||
AGREEMENT ON BEHALF OF SUCH ENTITY. IF YOU DO NOT HAVE SUCH AUTHORITY, DO NOT |
||||
COPY OR USE THE COMMERCIAL MODULES IN ANY MANNER. |
||||
|
||||
This Agreement is entered into by and between Bitwarden and you, or the legal |
||||
entity on behalf of whom you are acting (as applicable, "You" or "Your"). |
||||
|
||||
1. DEFINITIONS |
||||
|
||||
"Bitwarden Software" means the Bitwarden server software, libraries, and |
||||
Commercial Modules. |
||||
|
||||
"Commercial Modules" means the modules designed to work with and enhance the |
||||
Bitwarden Software to which this Agreement is linked, referenced, or appended. |
||||
|
||||
2. LICENSES, RESTRICTIONS AND THIRD PARTY CODE |
||||
|
||||
2.1 Commercial Module License. Subject to Your compliance with this Agreement, |
||||
Bitwarden hereby grants to You a limited, non-exclusive, non-transferable, |
||||
royalty-free license to use the Commercial Modules for the sole purposes of |
||||
internal development and internal testing, and only in a non-production |
||||
environment. |
||||
|
||||
2.2 Reservation of Rights. As between Bitwarden and You, Bitwarden owns all |
||||
right, title and interest in and to the Bitwarden Software, and except as |
||||
expressly set forth in Sections 2.1, no other license to the Bitwarden Software |
||||
is granted to You under this Agreement, by implication, estoppel, or otherwise. |
||||
|
||||
2.3 Restrictions. You agree not to: (i) except as expressly permitted in |
||||
Section 2.1, sell, rent, lease, distribute, sublicense, loan or otherwise |
||||
transfer the Commercial Modules to any third party; (ii) alter or remove any |
||||
trademarks, service mark, and logo included with the Commercial Modules, or |
||||
(iii) use the Commercial Modules to create a competing product or service. |
||||
Bitwarden is not obligated to provide maintenance and support services for the |
||||
Bitwarden Software licensed under this Agreement. |
||||
|
||||
2.4 Third Party Software. The Commercial Modules may contain or be provided |
||||
with third party open source libraries, components, utilities and other open |
||||
source software (collectively, "Open Source Software"). Notwithstanding anything |
||||
to the contrary herein, use of the Open Source Software will be subject to the |
||||
license terms and conditions applicable to such Open Source Software. To the |
||||
extent any condition of this Agreement conflicts with any license to the Open |
||||
Source Software, the Open Source Software license will govern with respect to |
||||
such Open Source Software only. |
||||
|
||||
2.5 This Agreement does not grant any rights in the trademarks, service marks, or |
||||
logos of any Contributor (except as may be necessary to comply with the notice |
||||
requirements in Section 2.3), and use of any Bitwarden trademarks must comply with |
||||
Bitwarden Trademark Guidelines |
||||
<https://github.com/bitwarden/server/blob/master/TRADEMARK_GUIDELINES.md>. |
||||
|
||||
3. TERMINATION |
||||
|
||||
3.1 Termination. This Agreement will automatically terminate upon notice from |
||||
Bitwarden, which notice may be by email or posting in the location where the |
||||
Commercial Modules are made available. |
||||
|
||||
3.2 Effect of Termination. Upon any termination of this Agreement, for any |
||||
reason, You will promptly cease use of the Commercial Modules and destroy any |
||||
copies thereof. For the avoidance of doubt, termination of this Agreement will |
||||
not affect Your right to Bitwarden Software, other than the Commercial Modules, |
||||
made available pursuant to an Open Source Software license. |
||||
|
||||
3.3 Survival. Sections 1, 2.2 -2.4, 3.2, 3.3, 4, and 5 will survive any |
||||
termination of this Agreement. |
||||
|
||||
4. DISCLAIMER AND LIMITATION OF LIABILITY |
||||
|
||||
4.1 Disclaimer of Warranties. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE |
||||
LAW, THE BITWARDEN SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, |
||||
EXPRESS OR IMPLIED REGARDING OR RELATING TO THE BITWARDEN SOFTWARE, INCLUDING |
||||
ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, |
||||
TITLE, AND NON-INFRINGEMENT. FURTHER, BITWARDEN DOES NOT WARRANT RESULTS OF USE |
||||
OR THAT THE BITWARDEN SOFTWARE WILL BE ERROR FREE OR THAT THE USE OF THE |
||||
BITWARDEN SOFTWARE WILL BE UNINTERRUPTED. |
||||
|
||||
4.2 Limitation of Liability. IN NO EVENT WILL BITWARDEN OR ITS LICENSORS BE |
||||
LIABLE TO YOU OR ANY THIRD PARTY UNDER THIS AGREEMENT FOR (I) ANY AMOUNTS IN |
||||
EXCESS OF US $25 OR (II) FOR ANY SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF |
||||
ANY KIND, INCLUDING FOR ANY LOSS OF PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, |
||||
LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, WHETHER ALLEGED AS A BREACH |
||||
OF CONTRACT OR TORTIOUS CONDUCT, INCLUDING NEGLIGENCE, EVEN IF BITWARDEN HAS |
||||
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. |
||||
|
||||
5. MISCELLANEOUS |
||||
|
||||
5.1 Assignment. You may not assign or otherwise transfer this Agreement or any |
||||
rights or obligations hereunder, in whole or in part, whether by operation of |
||||
law or otherwise, to any third party without Bitwarden's prior written consent. |
||||
Any purported transfer, assignment or delegation without such prior written |
||||
consent will be null and void and of no force or effect. Bitwarden may assign |
||||
this Agreement to any successor to its business or assets to which this |
||||
Agreement relates, whether by merger, sale of assets, sale of stock, |
||||
reorganization or otherwise. Subject to this Section 5.1, this Agreement will be |
||||
binding upon and inure to the benefit of the parties hereto, and their |
||||
respective successors and permitted assigns. |
||||
|
||||
5.2 Entire Agreement; Modification; Waiver. This Agreement represents the |
||||
entire agreement between the parties, and supersedes all prior agreements and |
||||
understandings, written or oral, with respect to the matters covered by this |
||||
Agreement, and is not intended to confer upon any third party any rights or |
||||
remedies hereunder. You acknowledge that You have not entered in this Agreement |
||||
based on any representations other than those contained herein. No modification |
||||
of or amendment to this Agreement, nor any waiver of any rights under this |
||||
Agreement, will be effective unless in writing and signed by both parties. The |
||||
waiver of one breach or default or any delay in exercising any rights will not |
||||
constitute a waiver of any subsequent breach or default. |
||||
|
||||
5.3 Governing Law. This Agreement will in all respects be governed by the laws |
||||
of the State of California without reference to its principles of conflicts of |
||||
laws. The parties hereby agree that all disputes arising out of this Agreement |
||||
will be subject to the exclusive jurisdiction of and venue in the federal and |
||||
state courts within Los Angeles County, California. You hereby consent to the |
||||
personal and exclusive jurisdiction and venue of these courts. The parties |
||||
hereby disclaim and exclude the application hereto of the United Nations |
||||
Convention on Contracts for the International Sale of Goods. |
||||
|
||||
5.4 Severability. If any provision of this Agreement is held invalid or |
||||
unenforceable under applicable law by a court of competent jurisdiction, it will |
||||
be replaced with the valid provision that most closely reflects the intent of |
||||
the parties and the remaining provisions of the Agreement will remain in full |
||||
force and effect. |
||||
|
||||
5.5 Relationship of the Parties. Nothing in this Agreement is to be construed |
||||
as creating an agency, partnership, or joint venture relationship between the |
||||
parties hereto. Neither party will have any right or authority to assume or |
||||
create any obligations or to make any representations or warranties on behalf of |
||||
any other party, whether express or implied, or to bind the other party in any |
||||
respect whatsoever. |
||||
|
||||
5.6 Notices. All notices permitted or required under this Agreement will be in |
||||
writing and will be deemed to have been given when delivered in person |
||||
(including by overnight courier), or three (3) business days after being mailed |
||||
by first class, registered or certified mail, postage prepaid, to the address of |
||||
the party specified in this Agreement or such other address as either party may |
||||
specify in writing. |
||||
|
||||
5.7 U.S. Government Restricted Rights. If Commercial Modules is being licensed |
||||
by the U.S. Government, the Commercial Modules is deemed to be "commercial |
||||
computer software" and "commercial computer documentation" developed exclusively |
||||
at private expense, and (a) if acquired by or on behalf of a civilian agency, |
||||
will be subject solely to the terms of this computer software license as |
||||
specified in 48 C.F.R. 12.212 of the Federal Acquisition Regulations and its |
||||
successors; and (b) if acquired by or on behalf of units of the Department of |
||||
Defense ("DOD") will be subject to the terms of this commercial computer |
||||
software license as specified in 48 C.F.R. 227.7202-2, DOD FAR Supplement and |
||||
its successors. |
||||
|
||||
5.8 Injunctive Relief. A breach or threatened breach by You of Section 2 may |
||||
cause irreparable harm for which damages at law may not provide adequate relief, |
||||
and therefore Bitwarden will be entitled to seek injunctive relief in any |
||||
applicable jurisdiction without being required to post a bond. |
||||
|
||||
5.9 Export Law Assurances. You understand that the Commercial Modules is |
||||
subject to export control laws and regulations. You may not download or |
||||
otherwise export or re-export the Commercial Modules or any underlying |
||||
information or technology except in full compliance with all applicable laws and |
||||
regulations, in particular, but without limitation, United States export control |
||||
laws. None of the Commercial Modules or any underlying information or technology |
||||
may be downloaded or otherwise exported or re- exported: (a) into (or to a |
||||
national or resident of) any country to which the United States has embargoed |
||||
goods; or (b) to anyone on the U.S. Treasury Department's list of specially |
||||
designated nationals or the U.S. Commerce Department's list of prohibited |
||||
countries or debarred or denied persons or entities. You hereby agree to the |
||||
foregoing and represents and warrants that You are not located in, under control |
||||
of, or a national or resident of any such country or on any such list. |
||||
|
||||
5.10 Construction. The titles and section headings used in this Agreement are |
||||
for ease of reference only and will not be used in the interpretation or |
||||
construction of this Agreement. No rule of construction resolving any ambiguity |
||||
in favor of the non-drafting party will be applied hereto. The word "including", |
||||
when used herein, is illustrative rather than exclusive and means "including, |
||||
without limitation." |
||||
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00 |
||||
# Visual Studio Version 16 |
||||
VisualStudioVersion = 16.0.31205.134 |
||||
MinimumVisualStudioVersion = 10.0.40219.1 |
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CryptoAgent", "src\CryptoAgent\CryptoAgent.csproj", "{CAD440BF-93C9-4DEC-B083-99FD49B50429}" |
||||
EndProject |
||||
Global |
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||
Debug|Any CPU = Debug|Any CPU |
||||
Release|Any CPU = Release|Any CPU |
||||
EndGlobalSection |
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||
{CAD440BF-93C9-4DEC-B083-99FD49B50429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
{CAD440BF-93C9-4DEC-B083-99FD49B50429}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
{CAD440BF-93C9-4DEC-B083-99FD49B50429}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
{CAD440BF-93C9-4DEC-B083-99FD49B50429}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
EndGlobalSection |
||||
GlobalSection(SolutionProperties) = preSolution |
||||
HideSolutionNode = FALSE |
||||
EndGlobalSection |
||||
GlobalSection(ExtensibilityGlobals) = postSolution |
||||
SolutionGuid = {40AD45DE-FF2B-4E64-9451-F368AA7C01E9} |
||||
EndGlobalSection |
||||
EndGlobal |
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
using Bit.CryptoAgent.Services; |
||||
using Microsoft.AspNetCore.Authorization; |
||||
using Microsoft.AspNetCore.Mvc; |
||||
using System; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Controllers |
||||
{ |
||||
public class MiscController : Controller |
||||
{ |
||||
private readonly IRsaKeyService _rsaKeyService; |
||||
|
||||
public MiscController( |
||||
IRsaKeyService rsaKeyService) |
||||
{ |
||||
_rsaKeyService = rsaKeyService; |
||||
} |
||||
|
||||
[HttpGet("~/alive")] |
||||
[HttpGet("~/now")] |
||||
[AllowAnonymous] |
||||
public DateTime GetAlive() |
||||
{ |
||||
return DateTime.UtcNow; |
||||
} |
||||
|
||||
[HttpGet("~/public-key")] |
||||
[AllowAnonymous] |
||||
public async Task<IActionResult> GetPublicKey() |
||||
{ |
||||
var key = await _rsaKeyService.GetPublicKeyAsync(); |
||||
return new OkObjectResult(new { PublicKey = Convert.ToBase64String(key) }); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,84 @@
@@ -0,0 +1,84 @@
|
||||
using Bit.CryptoAgent.Models; |
||||
using Bit.CryptoAgent.Repositories; |
||||
using Bit.CryptoAgent.Services; |
||||
using Microsoft.AspNetCore.Mvc; |
||||
using Microsoft.Extensions.Logging; |
||||
using System; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Controllers |
||||
{ |
||||
[Route("user-keys")] |
||||
public class UserKeysController : Controller |
||||
{ |
||||
private readonly ILogger<UserKeysController> _logger; |
||||
private readonly ICryptoService _cryptoService; |
||||
private readonly IUserKeyRepository _userKeyRepository; |
||||
|
||||
public UserKeysController( |
||||
ILogger<UserKeysController> logger, |
||||
IUserKeyRepository userKeyRepository, |
||||
ICryptoService cryptoService) |
||||
{ |
||||
_logger = logger; |
||||
_cryptoService = cryptoService; |
||||
_userKeyRepository = userKeyRepository; |
||||
} |
||||
|
||||
[HttpPost("{userId}/get")] |
||||
public async Task<IActionResult> Get(Guid userId, [FromBody] UserKeyGetRequestModel model) |
||||
{ |
||||
var publicKey = Convert.FromBase64String(model.PublicKey); |
||||
var user = await _userKeyRepository.ReadAsync(userId); |
||||
if (user == null) |
||||
{ |
||||
return new NotFoundResult(); |
||||
} |
||||
user.LastAccessDate = DateTime.UtcNow; |
||||
await _userKeyRepository.UpdateAsync(user); |
||||
var key = await _cryptoService.AesDecryptAsync(user.Key); |
||||
var encKey = await _cryptoService.RsaEncryptAsync(key, publicKey); |
||||
var response = new UserKeyResponseModel |
||||
{ |
||||
Key = Convert.ToBase64String(encKey) |
||||
}; |
||||
return new JsonResult(response); |
||||
} |
||||
|
||||
[HttpPost("{userId}")] |
||||
public async Task<IActionResult> Post(Guid userId, [FromBody] UserKeyRequestModel model) |
||||
{ |
||||
var user = await _userKeyRepository.ReadAsync(userId); |
||||
if (user != null) |
||||
{ |
||||
return new BadRequestResult(); |
||||
} |
||||
var key = await _cryptoService.RsaDecryptAsync(Convert.FromBase64String(model.Key)); |
||||
user = new UserKeyModel |
||||
{ |
||||
Id = userId, |
||||
Key = await _cryptoService.AesEncryptToB64Async(key) |
||||
}; |
||||
await _userKeyRepository.CreateAsync(user); |
||||
return new OkResult(); |
||||
} |
||||
|
||||
[HttpPut("{userId}")] |
||||
public async Task<IActionResult> Put(Guid userId, [FromBody] UserKeyRequestModel model) |
||||
{ |
||||
var user = await _userKeyRepository.ReadAsync(userId); |
||||
if (user != null) |
||||
{ |
||||
return new BadRequestResult(); |
||||
} |
||||
var key = await _cryptoService.RsaDecryptAsync(Convert.FromBase64String(model.Key)); |
||||
user = new UserKeyModel |
||||
{ |
||||
Id = userId, |
||||
Key = await _cryptoService.AesEncryptToB64Async(key) |
||||
}; |
||||
await _userKeyRepository.UpdateAsync(user); |
||||
return new OkResult(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>net5.0</TargetFramework> |
||||
<RootNamespace>Bit.CryptoAgent</RootNamespace> |
||||
<UserSecretsId>116f49e5-0b50-4080-856f-7e812413e723</UserSecretsId> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Azure.Identity" Version="1.4.1" /> |
||||
<PackageReference Include="Azure.Security.KeyVault.Certificates" Version="4.2.0" /> |
||||
<PackageReference Include="Azure.Security.KeyVault.Keys" Version="4.2.0" /> |
||||
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.2.0" /> |
||||
<PackageReference Include="Azure.Storage.Blobs" Version="12.9.1" /> |
||||
<PackageReference Include="JsonFlatFileDataStore" Version="2.2.3" /> |
||||
</ItemGroup> |
||||
|
||||
</Project> |
||||
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
namespace Bit.CryptoAgent |
||||
{ |
||||
public class CryptoAgentSettings |
||||
{ |
||||
public DatabaseSettings Database { get; set; } |
||||
public CertificateSettings Certificate { get; set; } |
||||
public RsaKeySettings RsaKey { get; set; } |
||||
|
||||
public class CertificateSettings |
||||
{ |
||||
// Filesystem |
||||
public string FilesystemPath { get; set; } |
||||
public string FilesystemPassword { get; set; } |
||||
// Local store |
||||
public string StoreThumbprint { get; set; } |
||||
// Azure blob storage |
||||
public string AzureStorageConnectionString { get; set; } |
||||
public string AzureStorageContainer { get; set; } |
||||
public string AzureStorageFileName { get; set; } |
||||
public string AzureStorageFilePassword { get; set; } |
||||
// Azure key vault |
||||
public string AzureKeyvaultUri { get; set; } |
||||
public string AzureKeyvaultCertificateName { get; set; } |
||||
public string AzureKeyvaultAdTenantId { get; set; } |
||||
public string AzureKeyvaultAdAppId { get; set; } |
||||
public string AzureKeyvaultAdSecret { get; set; } |
||||
} |
||||
|
||||
public class RsaKeySettings |
||||
{ |
||||
// Local certificate provider |
||||
public string Provider { get; set; } |
||||
// Azure key vault |
||||
public string AzureKeyvaultUri { get; set; } |
||||
public string AzureKeyvaultKeyName { get; set; } |
||||
public string AzureKeyvaultAdTenantId { get; set; } |
||||
public string AzureKeyvaultAdAppId { get; set; } |
||||
public string AzureKeyvaultAdSecret { get; set; } |
||||
// GCP... |
||||
// AWS... |
||||
// Hashicorp Vault... |
||||
// Other HSMs... |
||||
} |
||||
|
||||
public class DatabaseSettings |
||||
{ |
||||
public string JsonFilePath { get; set; } |
||||
public string SqlServerConnectionString { get; set; } |
||||
public string MySqlConnectionString { get; set; } |
||||
public string PostgreSqlConnectionString { get; set; } |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
using System; |
||||
|
||||
namespace Bit.CryptoAgent.Models |
||||
{ |
||||
public interface IStoredItem<TId> where TId : IEquatable<TId> |
||||
{ |
||||
public TId Id { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
using System; |
||||
using System.ComponentModel.DataAnnotations; |
||||
|
||||
namespace Bit.CryptoAgent.Models |
||||
{ |
||||
public class UserKeyGetRequestModel |
||||
{ |
||||
[Required] |
||||
public string PublicKey { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
using System; |
||||
|
||||
namespace Bit.CryptoAgent.Models |
||||
{ |
||||
public class UserKeyModel : BaseUserKeyModel, IStoredItem<Guid> |
||||
{ |
||||
public Guid Id { get; set; } |
||||
} |
||||
|
||||
public abstract class BaseUserKeyModel |
||||
{ |
||||
public string Key { get; set; } |
||||
public DateTime CreationDate { get; set; } = DateTime.UtcNow; |
||||
public DateTime? RevisionDate { get; set; } |
||||
public DateTime? LastAccessDate { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
using Bit.CryptoAgent.Services; |
||||
using System; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Models |
||||
{ |
||||
public class UserKeyRequestModel |
||||
{ |
||||
public string Key { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
namespace Bit.CryptoAgent.Models |
||||
{ |
||||
public class UserKeyResponseModel |
||||
{ |
||||
public string Key { get; set; } |
||||
} |
||||
} |
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
using Microsoft.AspNetCore.Hosting; |
||||
using Microsoft.Extensions.Hosting; |
||||
|
||||
namespace Bit.CryptoAgent |
||||
{ |
||||
public class Program |
||||
{ |
||||
public static void Main(string[] args) |
||||
{ |
||||
Host |
||||
.CreateDefaultBuilder(args) |
||||
.ConfigureWebHostDefaults(webBuilder => |
||||
{ |
||||
webBuilder.UseStartup<Startup>(); |
||||
}) |
||||
.Build() |
||||
.Run(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
{ |
||||
"iisSettings": { |
||||
"windowsAuthentication": false, |
||||
"anonymousAuthentication": true, |
||||
"iisExpress": { |
||||
"applicationUrl": "http://localhost:10253", |
||||
"sslPort": 0 |
||||
} |
||||
}, |
||||
"profiles": { |
||||
"IIS Express": { |
||||
"commandName": "IISExpress", |
||||
"launchBrowser": true, |
||||
"environmentVariables": { |
||||
"ASPNETCORE_ENVIRONMENT": "Development" |
||||
} |
||||
}, |
||||
"SsoAgent": { |
||||
"commandName": "Project", |
||||
"dotnetRunMessages": "true", |
||||
"launchBrowser": true, |
||||
"applicationUrl": "http://localhost:5000", |
||||
"environmentVariables": { |
||||
"ASPNETCORE_ENVIRONMENT": "Development" |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Repositories |
||||
{ |
||||
public interface IApplicationDataRepository |
||||
{ |
||||
Task<string> ReadSymmetricKeyAsync(); |
||||
Task UpdateSymmetricKeyAsync(string key); |
||||
} |
||||
} |
||||
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Repositories |
||||
{ |
||||
public interface IRepository<TItem, TId> |
||||
{ |
||||
Task CreateAsync(TItem item); |
||||
Task<TItem> ReadAsync(TId id); |
||||
Task UpdateAsync(TItem item); |
||||
Task DeleteAsync(TId id); |
||||
} |
||||
} |
||||
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
using Bit.CryptoAgent.Models; |
||||
using System; |
||||
|
||||
namespace Bit.CryptoAgent.Repositories |
||||
{ |
||||
public interface IUserKeyRepository : IRepository<UserKeyModel, Guid> |
||||
{ |
||||
} |
||||
} |
||||
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
using JsonFlatFileDataStore; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Repositories.JsonFile |
||||
{ |
||||
public class ApplicationDataRepository : IApplicationDataRepository |
||||
{ |
||||
public ApplicationDataRepository(IDataStore dataStore) |
||||
{ |
||||
DataStore = dataStore; |
||||
} |
||||
|
||||
protected IDataStore DataStore { get; private set; } |
||||
|
||||
public Task<string> ReadSymmetricKeyAsync() |
||||
{ |
||||
var item = DataStore.GetItem("symmetricKey"); |
||||
return Task.FromResult(item as string); |
||||
} |
||||
|
||||
public async Task UpdateSymmetricKeyAsync(string key) |
||||
{ |
||||
await DataStore.ReplaceItemAsync("symmetricKey", key, true); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
using Bit.CryptoAgent.Models; |
||||
using JsonFlatFileDataStore; |
||||
using System; |
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Repositories.JsonFile |
||||
{ |
||||
public class Repository<TItem, TId> : IRepository<TItem, TId> |
||||
where TId : IEquatable<TId> |
||||
where TItem : class, IStoredItem<TId> |
||||
{ |
||||
public Repository( |
||||
IDataStore dataStore, |
||||
string collectionName) |
||||
{ |
||||
DataStore = dataStore; |
||||
CollectionName = collectionName; |
||||
} |
||||
|
||||
protected IDataStore DataStore { get; private set; } |
||||
protected string CollectionName { get; private set; } |
||||
|
||||
public virtual async Task CreateAsync(TItem item) |
||||
{ |
||||
var collection = DataStore.GetCollection<TItem>(CollectionName); |
||||
await collection.InsertOneAsync(item); |
||||
} |
||||
|
||||
public virtual Task<TItem> ReadAsync(TId id) |
||||
{ |
||||
var collection = DataStore.GetCollection<TItem>(CollectionName); |
||||
var item = collection.AsQueryable().FirstOrDefault(i => i.Id.Equals(id)); |
||||
return Task.FromResult(item); |
||||
} |
||||
|
||||
public virtual async Task UpdateAsync(TItem item) |
||||
{ |
||||
var collection = DataStore.GetCollection<TItem>(CollectionName); |
||||
await collection.ReplaceOneAsync(item.Id, item); |
||||
} |
||||
|
||||
public virtual async Task DeleteAsync(TId id) |
||||
{ |
||||
var collection = DataStore.GetCollection<TItem>(CollectionName); |
||||
await collection.DeleteOneAsync(id); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
using Bit.CryptoAgent.Models; |
||||
using JsonFlatFileDataStore; |
||||
using System; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Repositories.JsonFile |
||||
{ |
||||
public class UserKeyRepository : Repository<UserKeyModel, Guid>, IUserKeyRepository |
||||
{ |
||||
public UserKeyRepository(IDataStore dataStore) |
||||
: base(dataStore, "userKey") |
||||
{ } |
||||
|
||||
public override async Task CreateAsync(UserKeyModel item) |
||||
{ |
||||
var collection = DataStore.GetCollection<JsonUserKeyModel>(CollectionName); |
||||
await collection.InsertOneAsync(new JsonUserKeyModel(item)); |
||||
} |
||||
|
||||
// New model is required since JsonFlatFileDataStore doesn't handle Guid id types |
||||
public class JsonUserKeyModel : BaseUserKeyModel |
||||
{ |
||||
public JsonUserKeyModel() { } |
||||
|
||||
public JsonUserKeyModel(UserKeyModel model) |
||||
{ |
||||
Id = model.Id.ToString(); |
||||
Key = model.Key; |
||||
CreationDate = model.CreationDate; |
||||
RevisionDate = model.RevisionDate; |
||||
LastAccessDate = model.LastAccessDate; |
||||
} |
||||
|
||||
public string Id { get; set; } |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
using Azure.Identity; |
||||
using Azure.Security.KeyVault.Certificates; |
||||
using Azure.Security.KeyVault.Secrets; |
||||
using System; |
||||
using System.Security.Cryptography.X509Certificates; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public class AzureKeyVaultCertificateProviderService : ICertificateProviderService |
||||
{ |
||||
private readonly CryptoAgentSettings _settings; |
||||
|
||||
public AzureKeyVaultCertificateProviderService(CryptoAgentSettings settings) |
||||
{ |
||||
_settings = settings; |
||||
} |
||||
|
||||
public async Task<X509Certificate2> GetCertificateAsync() |
||||
{ |
||||
var credential = new ClientSecretCredential(_settings.Certificate.AzureKeyvaultAdTenantId, |
||||
_settings.Certificate.AzureKeyvaultAdAppId, _settings.Certificate.AzureKeyvaultAdSecret); |
||||
var keyVaultUri = new Uri(_settings.Certificate.AzureKeyvaultUri); |
||||
|
||||
var certificateClient = new CertificateClient(keyVaultUri, credential); |
||||
var certificateResponse = await certificateClient.GetCertificateAsync( |
||||
_settings.Certificate.AzureKeyvaultCertificateName); |
||||
var certificate = certificateResponse.Value; |
||||
if (certificate.Policy?.Exportable == true && certificate.Policy?.KeyType == CertificateKeyType.Rsa) |
||||
{ |
||||
var secretName = ParseSecretName(certificate.SecretId); |
||||
var secretClient = new SecretClient(keyVaultUri, credential); |
||||
var secretResponse = await secretClient.GetSecretAsync(secretName); |
||||
var secret = secretResponse.Value; |
||||
if (string.Equals(secret.Properties.ContentType, CertificateContentType.Pkcs12.ToString(), |
||||
StringComparison.InvariantCultureIgnoreCase)) |
||||
{ |
||||
var pfxBytes = Convert.FromBase64String(secret.Value); |
||||
return new X509Certificate2(pfxBytes); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private string ParseSecretName(Uri secretId) |
||||
{ |
||||
if (secretId.Segments.Length < 3) |
||||
{ |
||||
throw new InvalidOperationException($@"The secret ""{secretId}"" does not contain a valid name."); |
||||
} |
||||
return secretId.Segments[2].TrimEnd('/'); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
using Azure.Identity; |
||||
using Azure.Security.KeyVault.Keys; |
||||
using Azure.Security.KeyVault.Keys.Cryptography; |
||||
using System; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public class AzureKeyVaultRsaKeyService : IRsaKeyService |
||||
{ |
||||
private readonly CryptoAgentSettings _settings; |
||||
|
||||
private KeyVaultKey _key; |
||||
private CryptographyClient _cryptographyClient; |
||||
private ClientSecretCredential _credential; |
||||
|
||||
public AzureKeyVaultRsaKeyService( |
||||
CryptoAgentSettings settings) |
||||
{ |
||||
_settings = settings; |
||||
} |
||||
|
||||
public async Task<byte[]> EncryptAsync(byte[] data) |
||||
{ |
||||
var client = await GetCryptographyClientAsync(); |
||||
var result = await client.EncryptAsync(EncryptionAlgorithm.RsaOaep, data); |
||||
return result.Ciphertext; |
||||
} |
||||
|
||||
public async Task<byte[]> DecryptAsync(byte[] data) |
||||
{ |
||||
var client = await GetCryptographyClientAsync(); |
||||
var result = await client.DecryptAsync(EncryptionAlgorithm.RsaOaep, data); |
||||
return result.Plaintext; |
||||
} |
||||
|
||||
public async Task<byte[]> SignAsync(byte[] data) |
||||
{ |
||||
var client = await GetCryptographyClientAsync(); |
||||
var result = await client.SignAsync(SignatureAlgorithm.RS256, data); |
||||
return result.Signature; |
||||
} |
||||
|
||||
public async Task<bool> VerifyAsync(byte[] data, byte[] signature) |
||||
{ |
||||
var client = await GetCryptographyClientAsync(); |
||||
var result = await client.VerifyDataAsync(SignatureAlgorithm.RS256, data, signature); |
||||
return result.IsValid; |
||||
} |
||||
|
||||
public async Task<byte[]> GetPublicKeyAsync() |
||||
{ |
||||
var key = await GetKeyAsync(); |
||||
return key.Key.ToRSA().ExportRSAPublicKey(); |
||||
} |
||||
|
||||
private async Task<CryptographyClient> GetCryptographyClientAsync() |
||||
{ |
||||
if (_cryptographyClient == null) |
||||
{ |
||||
var key = await GetKeyAsync(); |
||||
var credential = GetCredential(); |
||||
_cryptographyClient = new CryptographyClient(key.Id, credential); |
||||
} |
||||
return _cryptographyClient; |
||||
} |
||||
|
||||
private async Task<KeyVaultKey> GetKeyAsync() |
||||
{ |
||||
if (_key == null) |
||||
{ |
||||
var credential = GetCredential(); |
||||
var keyVaultUri = new Uri(_settings.RsaKey.AzureKeyvaultUri); |
||||
var keyClient = new KeyClient(keyVaultUri, credential); |
||||
_key = await keyClient.GetKeyAsync(_settings.RsaKey.AzureKeyvaultKeyName); |
||||
} |
||||
return _key; |
||||
} |
||||
|
||||
private ClientSecretCredential GetCredential() |
||||
{ |
||||
if (_credential == null) |
||||
{ |
||||
_credential = new ClientSecretCredential(_settings.RsaKey.AzureKeyvaultAdTenantId, |
||||
_settings.RsaKey.AzureKeyvaultAdAppId, _settings.RsaKey.AzureKeyvaultAdSecret); |
||||
} |
||||
return _credential; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
using Azure.Storage.Blobs; |
||||
using System.IO; |
||||
using System.Security.Cryptography.X509Certificates; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public class AzureStorageCertificateProviderService : ICertificateProviderService |
||||
{ |
||||
private readonly CryptoAgentSettings _settings; |
||||
|
||||
public AzureStorageCertificateProviderService(CryptoAgentSettings settings) |
||||
{ |
||||
_settings = settings; |
||||
} |
||||
|
||||
public async Task<X509Certificate2> GetCertificateAsync() |
||||
{ |
||||
var container = new BlobContainerClient(_settings.Certificate.AzureStorageConnectionString, |
||||
_settings.Certificate.AzureStorageContainer); |
||||
await container.CreateIfNotExistsAsync(); |
||||
var blobClient = container.GetBlobClient(_settings.Certificate.AzureStorageFileName); |
||||
if (await blobClient.ExistsAsync()) |
||||
{ |
||||
using var stream = new MemoryStream(); |
||||
await blobClient.DownloadToAsync(stream); |
||||
return new X509Certificate2(stream.ToArray(), _settings.Certificate.AzureStorageFilePassword); |
||||
} |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,99 @@
@@ -0,0 +1,99 @@
|
||||
using System; |
||||
using System.Security.Cryptography; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public class CryptoFunctionService : ICryptoFunctionService |
||||
{ |
||||
public async Task<byte[]> AesGcmEncryptAsync(byte[] data, byte[] key) |
||||
{ |
||||
using var aes = new AesGcm(key); |
||||
var iv = await GetRandomBytesAsync(AesGcm.NonceByteSizes.MaxSize); |
||||
var tag = new byte[AesGcm.TagByteSizes.MaxSize]; |
||||
var encData = new byte[data.Length]; |
||||
|
||||
aes.Encrypt(iv, data, encData, tag); |
||||
|
||||
var encResult = new byte[encData.Length + tag.Length + iv.Length]; |
||||
encData.CopyTo(encResult, 0); |
||||
tag.CopyTo(encResult, encData.Length); |
||||
iv.CopyTo(encResult, encData.Length + tag.Length); |
||||
|
||||
return encResult; |
||||
} |
||||
|
||||
public Task<byte[]> AesGcmDecryptAsync(byte[] data, byte[] key) |
||||
{ |
||||
using var aes = new AesGcm(key); |
||||
var endDataLength = data.Length - AesGcm.TagByteSizes.MaxSize - AesGcm.NonceByteSizes.MaxSize; |
||||
var encData = new ArraySegment<byte>(data, 0, endDataLength); |
||||
var tag = new ArraySegment<byte>(data, endDataLength, AesGcm.TagByteSizes.MaxSize); |
||||
var iv = new ArraySegment<byte>(data, endDataLength + AesGcm.TagByteSizes.MaxSize, AesGcm.NonceByteSizes.MaxSize); |
||||
var plainData = new byte[endDataLength]; |
||||
|
||||
aes.Decrypt(iv, encData, tag, plainData); |
||||
|
||||
return Task.FromResult(plainData); |
||||
} |
||||
|
||||
public Task<byte[]> RsaEncryptAsync(byte[] data, byte[] publicKey) |
||||
{ |
||||
using var rsa = RSA.Create(); |
||||
rsa.ImportSubjectPublicKeyInfo(publicKey, out var bytesRead); |
||||
return RsaEncryptAsync(data, rsa); |
||||
} |
||||
|
||||
public Task<byte[]> RsaEncryptAsync(byte[] data, RSA publicKey) |
||||
{ |
||||
var encData = publicKey.Encrypt(data, RSAEncryptionPadding.OaepSHA1); |
||||
return Task.FromResult(encData); |
||||
} |
||||
|
||||
public Task<byte[]> RsaDecryptAsync(byte[] data, byte[] privateKey) |
||||
{ |
||||
using var rsa = RSA.Create(); |
||||
rsa.ImportPkcs8PrivateKey(privateKey, out var bytesRead); |
||||
return RsaDecryptAsync(data, rsa); |
||||
} |
||||
|
||||
public Task<byte[]> RsaDecryptAsync(byte[] data, RSA privateKey) |
||||
{ |
||||
var encData = privateKey.Decrypt(data, RSAEncryptionPadding.OaepSHA1); |
||||
return Task.FromResult(encData); |
||||
} |
||||
|
||||
public Task<bool> RsaVerifyAsync(byte[] data, byte[] signature, byte[] publicKey) |
||||
{ |
||||
using var rsa = RSA.Create(); |
||||
rsa.ImportSubjectPublicKeyInfo(publicKey, out var bytesRead); |
||||
return RsaVerifyAsync(data, signature, rsa); |
||||
} |
||||
|
||||
public Task<bool> RsaVerifyAsync(byte[] data, byte[] signature, RSA publicKey) |
||||
{ |
||||
var valid = publicKey.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); |
||||
return Task.FromResult(valid); |
||||
} |
||||
|
||||
public Task<byte[]> RsaSignAsync(byte[] data, byte[] privateKey) |
||||
{ |
||||
using var rsa = RSA.Create(); |
||||
rsa.ImportPkcs8PrivateKey(privateKey, out var bytesRead); |
||||
return RsaSignAsync(data, rsa); |
||||
} |
||||
|
||||
public Task<byte[]> RsaSignAsync(byte[] data, RSA privateKey) |
||||
{ |
||||
var signature = privateKey.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); |
||||
return Task.FromResult(signature); |
||||
} |
||||
|
||||
public Task<byte[]> GetRandomBytesAsync(int size) |
||||
{ |
||||
var bytes = new byte[size]; |
||||
RandomNumberGenerator.Fill(bytes); |
||||
return Task.FromResult(bytes); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,162 @@
@@ -0,0 +1,162 @@
|
||||
using Bit.CryptoAgent.Repositories; |
||||
using System; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public class CryptoService : ICryptoService |
||||
{ |
||||
private readonly IRsaKeyService _rsaKeyService; |
||||
private readonly ICryptoFunctionService _cryptoFunctionService; |
||||
private readonly IApplicationDataRepository _applicationDataRepository; |
||||
|
||||
private byte[] _symmetricKey; |
||||
|
||||
public CryptoService( |
||||
IRsaKeyService rsaKeyService, |
||||
ICryptoFunctionService cryptoFunctionService, |
||||
IApplicationDataRepository applicationDataRepository) |
||||
{ |
||||
_rsaKeyService = rsaKeyService; |
||||
_cryptoFunctionService = cryptoFunctionService; |
||||
_applicationDataRepository = applicationDataRepository; |
||||
} |
||||
|
||||
// AES Decrypt |
||||
|
||||
public async Task<byte[]> AesDecryptAsync(byte[] data, byte[] key = null) |
||||
{ |
||||
if (data == null) |
||||
{ |
||||
return null; |
||||
} |
||||
if (key == null) |
||||
{ |
||||
key = await GetSymmetricKeyAsync(); |
||||
} |
||||
var plainData = await _cryptoFunctionService.AesGcmDecryptAsync(data, key); |
||||
return plainData; |
||||
} |
||||
|
||||
public async Task<string> AesDecryptToB64Async(byte[] data, byte[] key = null) |
||||
{ |
||||
var plainData = await AesDecryptAsync(data, key); |
||||
return Convert.ToBase64String(plainData); |
||||
} |
||||
|
||||
public async Task<byte[]> AesDecryptAsync(string b64Data, byte[] key = null) |
||||
{ |
||||
var data = Convert.FromBase64String(b64Data); |
||||
var plainData = await AesDecryptAsync(data, key); |
||||
return plainData; |
||||
} |
||||
|
||||
public async Task<string> AesDecryptToB64Async(string b64Data, byte[] key = null) |
||||
{ |
||||
var data = Convert.FromBase64String(b64Data); |
||||
var plainData = await AesDecryptToB64Async(data, key); |
||||
return plainData; |
||||
} |
||||
|
||||
// AES Encrypt |
||||
|
||||
public async Task<byte[]> AesEncryptAsync(byte[] data, byte[] key = null) |
||||
{ |
||||
if (data == null) |
||||
{ |
||||
return null; |
||||
} |
||||
if (key == null) |
||||
{ |
||||
key = await GetSymmetricKeyAsync(); |
||||
} |
||||
var encData = await _cryptoFunctionService.AesGcmEncryptAsync(data, key); |
||||
return encData; |
||||
} |
||||
|
||||
public async Task<byte[]> AesEncryptAsync(string b64Data, byte[] key = null) |
||||
{ |
||||
var data = Convert.FromBase64String(b64Data); |
||||
var encData = await AesEncryptAsync(data, key); |
||||
return encData; |
||||
} |
||||
|
||||
public async Task<string> AesEncryptToB64Async(byte[] data, byte[] key = null) |
||||
{ |
||||
var encData = await AesEncryptAsync(data, key); |
||||
return Convert.ToBase64String(encData); |
||||
} |
||||
|
||||
public async Task<string> AesEncryptToB64Async(string b64Data, byte[] key = null) |
||||
{ |
||||
var encData = await AesEncryptAsync(b64Data, key); |
||||
return Convert.ToBase64String(encData); |
||||
} |
||||
|
||||
// RSA Encrypt |
||||
|
||||
public async Task<byte[]> RsaEncryptAsync(byte[] data, byte[] publicKey = null) |
||||
{ |
||||
if (data == null) |
||||
{ |
||||
return null; |
||||
} |
||||
if (publicKey == null) |
||||
{ |
||||
return await _rsaKeyService.EncryptAsync(data); |
||||
} |
||||
var encData = await _cryptoFunctionService.RsaEncryptAsync(data, publicKey); |
||||
return encData; |
||||
} |
||||
|
||||
// RSA Decrypt |
||||
|
||||
public async Task<byte[]> RsaDecryptAsync(byte[] data) |
||||
{ |
||||
if (data == null) |
||||
{ |
||||
return null; |
||||
} |
||||
return await _rsaKeyService.DecryptAsync(data); |
||||
} |
||||
|
||||
// RSA Verify |
||||
|
||||
public async Task<bool> RsaVerifyAsync(byte[] data, byte[] signature, byte[] publicKey = null) |
||||
{ |
||||
if (data == null || signature == null) |
||||
{ |
||||
return false; |
||||
} |
||||
if (publicKey == null) |
||||
{ |
||||
return await _rsaKeyService.VerifyAsync(data, signature); |
||||
} |
||||
return await _cryptoFunctionService.RsaVerifyAsync(data, signature, publicKey); |
||||
} |
||||
|
||||
// Helpers |
||||
|
||||
private async Task<byte[]> GetSymmetricKeyAsync() |
||||
{ |
||||
if (_symmetricKey == null) |
||||
{ |
||||
var encKey = await _applicationDataRepository.ReadSymmetricKeyAsync(); |
||||
if (encKey != null) |
||||
{ |
||||
var decodedEncKey = Convert.FromBase64String(encKey); |
||||
_symmetricKey = await RsaDecryptAsync(decodedEncKey); |
||||
} |
||||
else |
||||
{ |
||||
_symmetricKey = await _cryptoFunctionService.GetRandomBytesAsync(32); |
||||
var decodedEncKey = await RsaEncryptAsync(_symmetricKey); |
||||
encKey = Convert.ToBase64String(decodedEncKey); |
||||
await _applicationDataRepository.UpdateSymmetricKeyAsync(encKey); |
||||
} |
||||
} |
||||
|
||||
return _symmetricKey; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
using System.Security.Cryptography.X509Certificates; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public class FilesystemCertificateProviderService : ICertificateProviderService |
||||
{ |
||||
private readonly CryptoAgentSettings _settings; |
||||
|
||||
public FilesystemCertificateProviderService(CryptoAgentSettings settings) |
||||
{ |
||||
_settings = settings; |
||||
} |
||||
|
||||
public Task<X509Certificate2> GetCertificateAsync() |
||||
{ |
||||
var cert = new X509Certificate2(_settings.Certificate.FilesystemPath, |
||||
_settings.Certificate.FilesystemPassword); |
||||
return Task.FromResult(cert); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
using System.Security.Cryptography.X509Certificates; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public interface ICertificateProviderService |
||||
{ |
||||
Task<X509Certificate2> GetCertificateAsync(); |
||||
} |
||||
} |
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
using System.Security.Cryptography; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public interface ICryptoFunctionService |
||||
{ |
||||
Task<byte[]> AesGcmDecryptAsync(byte[] data, byte[] key); |
||||
Task<byte[]> AesGcmEncryptAsync(byte[] data, byte[] key); |
||||
Task<byte[]> RsaDecryptAsync(byte[] data, byte[] privateKey); |
||||
Task<byte[]> RsaDecryptAsync(byte[] data, RSA privateKey); |
||||
Task<byte[]> RsaEncryptAsync(byte[] data, byte[] publicKey); |
||||
Task<byte[]> RsaEncryptAsync(byte[] data, RSA publicKey); |
||||
Task<byte[]> RsaSignAsync(byte[] data, byte[] privateKey); |
||||
Task<byte[]> RsaSignAsync(byte[] data, RSA privateKey); |
||||
Task<bool> RsaVerifyAsync(byte[] data, byte[] signature, byte[] publicKey); |
||||
Task<bool> RsaVerifyAsync(byte[] data, byte[] signature, RSA publicKey); |
||||
Task<byte[]> GetRandomBytesAsync(int size); |
||||
} |
||||
} |
||||
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public interface ICryptoService |
||||
{ |
||||
Task<byte[]> AesDecryptAsync(byte[] data, byte[] key = null); |
||||
Task<byte[]> AesDecryptAsync(string b64Data, byte[] key = null); |
||||
Task<string> AesDecryptToB64Async(byte[] data, byte[] key = null); |
||||
Task<string> AesDecryptToB64Async(string b64Data, byte[] key = null); |
||||
Task<byte[]> AesEncryptAsync(byte[] data, byte[] key = null); |
||||
Task<byte[]> AesEncryptAsync(string b64Data, byte[] key = null); |
||||
Task<string> AesEncryptToB64Async(byte[] data, byte[] key = null); |
||||
Task<string> AesEncryptToB64Async(string b64Data, byte[] key = null); |
||||
Task<byte[]> RsaEncryptAsync(byte[] data, byte[] publicKey = null); |
||||
Task<byte[]> RsaDecryptAsync(byte[] data); |
||||
Task<bool> RsaVerifyAsync(byte[] data, byte[] signature, byte[] publicKey = null); |
||||
} |
||||
} |
||||
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public interface IRsaKeyService |
||||
{ |
||||
Task<byte[]> DecryptAsync(byte[] data); |
||||
Task<byte[]> EncryptAsync(byte[] data); |
||||
Task<byte[]> SignAsync(byte[] data); |
||||
Task<bool> VerifyAsync(byte[] data, byte[] signature); |
||||
Task<byte[]> GetPublicKeyAsync(); |
||||
} |
||||
} |
||||
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
using System.Security.Cryptography.X509Certificates; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public class LocalCertificateRsaKeyService : IRsaKeyService |
||||
{ |
||||
private readonly ICertificateProviderService _certificateProviderService; |
||||
private readonly ICryptoFunctionService _cryptoFunctionService; |
||||
|
||||
private X509Certificate2 _certificate; |
||||
|
||||
public LocalCertificateRsaKeyService( |
||||
ICertificateProviderService certificateProviderService, |
||||
ICryptoFunctionService cryptoFunctionService) |
||||
{ |
||||
_certificateProviderService = certificateProviderService; |
||||
_cryptoFunctionService = cryptoFunctionService; |
||||
} |
||||
|
||||
public async Task<byte[]> EncryptAsync(byte[] data) |
||||
{ |
||||
if (data == null) |
||||
{ |
||||
return null; |
||||
} |
||||
var encData = await _cryptoFunctionService.RsaEncryptAsync(data, await GetPublicKeyAsync()); |
||||
return encData; |
||||
} |
||||
|
||||
public async Task<byte[]> DecryptAsync(byte[] data) |
||||
{ |
||||
if (data == null) |
||||
{ |
||||
return null; |
||||
} |
||||
var plainData = await _cryptoFunctionService.RsaDecryptAsync(data, await GetPrivateKeyAsync()); |
||||
return plainData; |
||||
} |
||||
|
||||
public async Task<byte[]> SignAsync(byte[] data) |
||||
{ |
||||
if (data == null) |
||||
{ |
||||
return null; |
||||
} |
||||
return await _cryptoFunctionService.RsaSignAsync(data, await GetPrivateKeyAsync()); |
||||
} |
||||
|
||||
public async Task<bool> VerifyAsync(byte[] data, byte[] signature) |
||||
{ |
||||
if (data == null || signature == null) |
||||
{ |
||||
return false; |
||||
} |
||||
return await _cryptoFunctionService.RsaVerifyAsync(data, signature, await GetPublicKeyAsync()); |
||||
} |
||||
|
||||
public async Task<byte[]> GetPublicKeyAsync() |
||||
{ |
||||
var certificate = await GetCertificateAsync(); |
||||
return certificate.GetRSAPublicKey().ExportRSAPublicKey(); |
||||
} |
||||
|
||||
private async Task<X509Certificate2> GetCertificateAsync() |
||||
{ |
||||
if (_certificate == null) |
||||
{ |
||||
_certificate = await _certificateProviderService.GetCertificateAsync(); |
||||
} |
||||
|
||||
return _certificate; |
||||
} |
||||
|
||||
private async Task<System.Security.Cryptography.RSA> GetPrivateKeyAsync() |
||||
{ |
||||
var certificate = await GetCertificateAsync(); |
||||
return certificate.GetRSAPrivateKey(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
using System.Security.Cryptography.X509Certificates; |
||||
using System.Text.RegularExpressions; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Bit.CryptoAgent.Services |
||||
{ |
||||
public class StoreCertificateProviderService : ICertificateProviderService |
||||
{ |
||||
private readonly CryptoAgentSettings _settings; |
||||
|
||||
public StoreCertificateProviderService(CryptoAgentSettings settings) |
||||
{ |
||||
_settings = settings; |
||||
} |
||||
|
||||
public Task<X509Certificate2> GetCertificateAsync() |
||||
{ |
||||
X509Certificate2 cert = null; |
||||
var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser); |
||||
certStore.Open(OpenFlags.ReadOnly); |
||||
var certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, |
||||
CleanThumbprint(_settings.Certificate.StoreThumbprint), false); |
||||
if (certCollection.Count > 0) |
||||
{ |
||||
cert = certCollection[0]; |
||||
} |
||||
certStore.Close(); |
||||
return Task.FromResult(cert); |
||||
} |
||||
|
||||
public static string CleanThumbprint(string thumbprint) |
||||
{ |
||||
// Clean possible garbage characters from thumbprint copy/paste |
||||
// ref http://stackoverflow.com/questions/8448147/problems-with-x509store-certificates-find-findbythumbprint |
||||
return Regex.Replace(thumbprint, @"[^\da-fA-F]", string.Empty).ToUpper(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,104 @@
@@ -0,0 +1,104 @@
|
||||
using Bit.CryptoAgent.Repositories; |
||||
using Bit.CryptoAgent.Services; |
||||
using JsonFlatFileDataStore; |
||||
using Microsoft.AspNetCore.Builder; |
||||
using Microsoft.AspNetCore.Hosting; |
||||
using Microsoft.Extensions.Configuration; |
||||
using Microsoft.Extensions.DependencyInjection; |
||||
using Microsoft.Extensions.Hosting; |
||||
using System; |
||||
using System.Globalization; |
||||
|
||||
namespace Bit.CryptoAgent |
||||
{ |
||||
public class Startup |
||||
{ |
||||
public Startup(IWebHostEnvironment env, IConfiguration configuration) |
||||
{ |
||||
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); |
||||
Configuration = configuration; |
||||
Environment = env; |
||||
} |
||||
|
||||
public IConfiguration Configuration { get; } |
||||
public IWebHostEnvironment Environment { get; set; } |
||||
|
||||
public void ConfigureServices(IServiceCollection services) |
||||
{ |
||||
var settings = new CryptoAgentSettings(); |
||||
ConfigurationBinder.Bind(Configuration.GetSection("CryptoAgentSettings"), settings); |
||||
services.AddSingleton(s => settings); |
||||
|
||||
var rsaKeyProvider = settings.RsaKey.Provider?.ToLowerInvariant(); |
||||
if (rsaKeyProvider == "certificate") |
||||
{ |
||||
services.AddSingleton<IRsaKeyService, LocalCertificateRsaKeyService>(); |
||||
|
||||
if (!string.IsNullOrWhiteSpace(settings.Certificate?.StoreThumbprint)) |
||||
{ |
||||
services.AddSingleton<ICertificateProviderService, StoreCertificateProviderService>(); |
||||
} |
||||
else if (!string.IsNullOrWhiteSpace(settings.Certificate?.FilesystemPath)) |
||||
{ |
||||
services.AddSingleton<ICertificateProviderService, FilesystemCertificateProviderService>(); |
||||
} |
||||
else if (!string.IsNullOrWhiteSpace(settings.Certificate?.AzureStorageConnectionString)) |
||||
{ |
||||
services.AddSingleton<ICertificateProviderService, AzureStorageCertificateProviderService>(); |
||||
} |
||||
else if (!string.IsNullOrWhiteSpace(settings.Certificate?.AzureKeyvaultUri)) |
||||
{ |
||||
services.AddSingleton<ICertificateProviderService, AzureKeyVaultCertificateProviderService>(); |
||||
} |
||||
else |
||||
{ |
||||
throw new Exception("No certificate provider configured."); |
||||
} |
||||
} |
||||
else if (rsaKeyProvider == "azure") |
||||
{ |
||||
if (!string.IsNullOrWhiteSpace(settings.RsaKey?.AzureKeyvaultUri)) |
||||
{ |
||||
services.AddSingleton<IRsaKeyService, AzureKeyVaultRsaKeyService>(); |
||||
} |
||||
else |
||||
{ |
||||
throw new Exception("No azure key vault configured."); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
throw new Exception("Unknown rsa key provider."); |
||||
} |
||||
|
||||
services.AddSingleton<ICryptoFunctionService, CryptoFunctionService>(); |
||||
services.AddSingleton<ICryptoService, CryptoService>(); |
||||
|
||||
// JsonFlatFileDataStore |
||||
if (!string.IsNullOrWhiteSpace(settings.Database?.JsonFilePath)) |
||||
{ |
||||
// Assign foobar to keyProperty in order to not use incrementing Id functionality |
||||
services.AddSingleton<IDataStore>(new DataStore(settings.Database.JsonFilePath, keyProperty: "--foobar--")); |
||||
services.AddSingleton<IApplicationDataRepository, Repositories.JsonFile.ApplicationDataRepository>(); |
||||
services.AddSingleton<IUserKeyRepository, Repositories.JsonFile.UserKeyRepository>(); |
||||
} |
||||
else |
||||
{ |
||||
throw new Exception("No database configured."); |
||||
} |
||||
|
||||
services.AddControllers(); |
||||
} |
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) |
||||
{ |
||||
if (env.IsDevelopment()) |
||||
{ |
||||
app.UseDeveloperExceptionPage(); |
||||
} |
||||
|
||||
app.UseRouting(); |
||||
app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute()); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
{ |
||||
"Logging": { |
||||
"LogLevel": { |
||||
"Default": "Information", |
||||
"Microsoft": "Warning", |
||||
"Microsoft.Hosting.Lifetime": "Information" |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
{ |
||||
"Logging": { |
||||
"LogLevel": { |
||||
"Default": "Information", |
||||
"Microsoft": "Warning", |
||||
"Microsoft.Hosting.Lifetime": "Information" |
||||
} |
||||
}, |
||||
"AllowedHosts": "*", |
||||
"cryptoAgentSettings": { |
||||
"rsaKey": { |
||||
"provider": "certificate" |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue