Compare commits

...

4 Commits

Author SHA1 Message Date
morbalint 978618d1b1 [be] open telemetry: only log to console when no other exporter exists 2024-01-23 13:31:22 +01:00
morbalint 65132fc7c6 add open telemetry and refactor setup 2024-01-23 13:10:16 +01:00
morbalint 8abe228d89 [fe] improve first time save UX 2024-01-22 12:51:40 +01:00
morbalint cc9a83607c use the official discord button on registration page as well
and disable the not yet approved external login providers on the registration page
2024-01-21 15:25:37 +01:00
9 changed files with 336 additions and 27 deletions
@@ -116,6 +116,12 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
// Disable not yet approved external login providers in production
if (!_environment.IsDevelopment())
{
ExternalLogins = ExternalLogins.Where(el => el.Name == "Discord").ToList();
}
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
// This doesn't count login failures towards account lockout // This doesn't count login failures towards account lockout
@@ -49,7 +49,8 @@
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal"> <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
<div> <div>
<p> <p>
@foreach (var provider in Model.ExternalLogins!) <button type="submit" class="btn" name="provider" value="Discord" title="Log in using your Discord account"><img height="24px" alt="Discord" src="/img/discord-logo-blue.svg" /></button>
@foreach (var provider in Model.ExternalLogins!.Where(el => el.Name != "Discord"))
{ {
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button> <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
} }
@@ -30,13 +30,15 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
private readonly IUserEmailStore<ApplicationUser> _emailStore; private readonly IUserEmailStore<ApplicationUser> _emailStore;
private readonly ILogger<RegisterModel> _logger; private readonly ILogger<RegisterModel> _logger;
private readonly IEmailSender _emailSender; private readonly IEmailSender _emailSender;
private readonly IWebHostEnvironment _environment;
public RegisterModel( public RegisterModel(
UserManager<ApplicationUser> userManager, UserManager<ApplicationUser> userManager,
IUserStore<ApplicationUser> userStore, IUserStore<ApplicationUser> userStore,
SignInManager<ApplicationUser> signInManager, SignInManager<ApplicationUser> signInManager,
ILogger<RegisterModel> logger, ILogger<RegisterModel> logger,
IEmailSender emailSender) IEmailSender emailSender,
IWebHostEnvironment environment)
{ {
_userManager = userManager; _userManager = userManager;
_userStore = userStore; _userStore = userStore;
@@ -44,6 +46,7 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
_signInManager = signInManager; _signInManager = signInManager;
_logger = logger; _logger = logger;
_emailSender = emailSender; _emailSender = emailSender;
_environment = environment;
} }
/// <summary> /// <summary>
@@ -105,12 +108,22 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
{ {
ReturnUrl = returnUrl; ReturnUrl = returnUrl;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
// Disable not yet approved external login providers in production
if (!_environment.IsDevelopment())
{
ExternalLogins = ExternalLogins.Where(el => el.Name == "Discord").ToList();
}
} }
public async Task<IActionResult> OnPostAsync(string returnUrl = null) public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{ {
returnUrl ??= Url.Content("~/"); returnUrl ??= Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
// Disable not yet approved external login providers in production
if (!_environment.IsDevelopment())
{
ExternalLogins = ExternalLogins.Where(el => el.Name == "Discord").ToList();
}
if (!ModelState.IsValid) if (!ModelState.IsValid)
{ {
return Page(); return Page();
+10
View File
@@ -0,0 +1,10 @@
namespace Kemkas.Web.Config;
public class ExternalAuthOptions
{
public string? ClientId { get; set; }
public string? ClientSecret { get; set; }
public bool IsValid() => ClientId != null && ClientSecret != null;
}
@@ -0,0 +1,84 @@
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
namespace Kemkas.Web.Config;
public static class WebApplicationBuilderExtensions
{
public static void AddAuth(this WebApplicationBuilder builder)
{
var externalAuthConfigSection = builder.Configuration.GetSection("Authentication");
var authenticationBuilder = builder.Services.AddAuthentication();
var googleAuthOptions = new ExternalAuthOptions();
externalAuthConfigSection.GetSection("Google").Bind(googleAuthOptions);
if (googleAuthOptions.IsValid())
{
authenticationBuilder.AddGoogle(options =>
{
options.ClientId = googleAuthOptions.ClientId!;
options.ClientSecret = googleAuthOptions.ClientSecret!;
});
}
var facebookAuthOptions = new ExternalAuthOptions();
externalAuthConfigSection.GetSection("Facebook").Bind(facebookAuthOptions);
if (facebookAuthOptions.IsValid())
{
authenticationBuilder.AddFacebook(options =>
{
options.ClientId = facebookAuthOptions.ClientId!;
options.ClientSecret = facebookAuthOptions.ClientSecret!;
});
}
var discordAuthOptions = new ExternalAuthOptions();
externalAuthConfigSection.GetSection("Discord").Bind(discordAuthOptions);
if (discordAuthOptions.IsValid())
{
authenticationBuilder.AddDiscord(options =>
{
options.ClientId = discordAuthOptions.ClientId!;
options.ClientSecret = discordAuthOptions.ClientSecret!;
});
}
}
public static void AddOpenTelemetry(this WebApplicationBuilder builder)
{
var otlResourceBuilder = ResourceBuilder.CreateDefault().AddService("kemkas-api");
var openTelemetryEndpoint = builder.Configuration.GetSection("monitoring")["url"];
builder.Services.AddOpenTelemetry().WithTracing(tracerProviderBuilder =>
{
tracerProviderBuilder
.SetResourceBuilder(otlResourceBuilder)
.AddAspNetCoreInstrumentation();
if (openTelemetryEndpoint != null)
{
tracerProviderBuilder.AddOtlpExporter(opt => opt.Endpoint = new Uri(openTelemetryEndpoint));
}
else
{
tracerProviderBuilder.AddConsoleExporter();
}
})
.WithMetrics(meterProviderBuilder =>
{
meterProviderBuilder
.SetResourceBuilder(otlResourceBuilder)
.AddAspNetCoreInstrumentation();
if (openTelemetryEndpoint != null)
{
meterProviderBuilder.AddOtlpExporter(opt => opt.Endpoint = new Uri(openTelemetryEndpoint));
}
else
{
meterProviderBuilder.AddConsoleExporter();
}
});
}
}
+5
View File
@@ -18,6 +18,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNet.Security.OAuth.Discord" Version="8.0.0" /> <PackageReference Include="AspNet.Security.OAuth.Discord" Version="8.0.0" />
<PackageReference Include="Grpc.Core" Version="2.46.6" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Facebook" Version="8.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.Facebook" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="8.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="8.0.0" /> <PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="8.0.0" />
@@ -36,6 +37,10 @@
</PackageReference> </PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="1.1.0" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="1.1.0" />
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+10 -19
View File
@@ -11,6 +11,9 @@ using Kemkas.Web.Services.Identity;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.AspNetCore.Identity.UI.Services;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork; using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@@ -34,25 +37,7 @@ builder.Services.AddSingleton<IEmailSender, MailgunEmailSender>();
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>(); .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddAuthentication() builder.AddAuth();
.AddGoogle(options =>
{
var section = builder.Configuration.GetSection("Authentication:Google");
options.ClientId = section["ClientId"];
options.ClientSecret = section["ClientSecret"];
})
.AddFacebook(options =>
{
var section = builder.Configuration.GetSection("Authentication:Facebook");
options.ClientId = section["ClientId"];
options.ClientSecret = section["ClientSecret"];
})
.AddDiscord(options =>
{
var section = builder.Configuration.GetSection("Authentication:Discord");
options.ClientId = section["ClientId"];
options.ClientSecret = section["ClientSecret"];
});
builder.Services.AddControllersWithViews().AddJsonOptions(options => builder.Services.AddControllersWithViews().AddJsonOptions(options =>
{ {
@@ -62,6 +47,10 @@ builder.Services.AddControllersWithViews().AddJsonOptions(options =>
}); });
builder.Services.AddRazorPages(); builder.Services.AddRazorPages();
builder.AddOpenTelemetry();
builder.Services.AddHealthChecks();
builder.Services.AddCharacterServices(); builder.Services.AddCharacterServices();
var app = builder.Build(); var app = builder.Build();
@@ -93,6 +82,8 @@ else
app.UseHsts(); // TODO: check if this should be handled by proxy app.UseHsts(); // TODO: check if this should be handled by proxy
} }
app.UseHealthChecks("/health");
await using (var scope = app.Services.CreateAsyncScope()) await using (var scope = app.Services.CreateAsyncScope())
{ {
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>(); var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
@@ -21,7 +21,8 @@ import {CalculateMasodlagosErtekek} from "../domain-models/masodlagos_ertekek";
import {KarakterInputToPdfView} from "../pdf/karakter_pdf_view"; import {KarakterInputToPdfView} from "../pdf/karakter_pdf_view";
import JellemSelector from "../components/JellemSelector"; import JellemSelector from "../components/JellemSelector";
import {CanLevelUp, LevelDown, LevelUp} from "../domain-models/level"; import {CanLevelUp, LevelDown, LevelUp} from "../domain-models/level";
import {Card, OverlayTrigger, Toast, ToastContainer} from "react-bootstrap"; import {Button, Card, InputGroup, Modal, OverlayTrigger, Toast, ToastContainer} from "react-bootstrap";
import Form from "react-bootstrap/Form";
import LevelUps from "../components/LevelUps"; import LevelUps from "../components/LevelUps";
import HarcosFegyverSpecializacio from "../components/HarcosFegyverSpecializacio"; import HarcosFegyverSpecializacio from "../components/HarcosFegyverSpecializacio";
import Felszereles from '../components/Felszereles'; import Felszereles from '../components/Felszereles';
@@ -39,7 +40,6 @@ function CreateCharacterPage(props: {
const {faro} = props const {faro} = props
const loaderData = useLoaderData() as KarakterInputs & { isPublic: boolean } | undefined; const loaderData = useLoaderData() as KarakterInputs & { isPublic: boolean } | undefined;
const initialIsPublic = loaderData?.isPublic ?? false;
let initialKarakterInputs = KarakterDefaults; let initialKarakterInputs = KarakterDefaults;
if (loaderData != null) { if (loaderData != null) {
const { isPublic: t1, ...t2 } = loaderData; const { isPublic: t1, ...t2 } = loaderData;
@@ -47,6 +47,9 @@ function CreateCharacterPage(props: {
} }
const { id } = useParams(); const { id } = useParams();
const fetchedUser = useContext(UserContext); const fetchedUser = useContext(UserContext);
const initialIsPublic = loaderData?.isPublic ?? fetchedUser?.data == null;
const navigate = useNavigate(); const navigate = useNavigate();
let [karakter, changeKarakter] = useState(initialKarakterInputs) let [karakter, changeKarakter] = useState(initialKarakterInputs)
@@ -66,9 +69,25 @@ function CreateCharacterPage(props: {
const canLevelUp = CanLevelUp(karakter) const canLevelUp = CanLevelUp(karakter)
let [showSaveModal, setShowSaveModal] = useState(false);
let [newId, setNewId] = useState(null as string | null)
let [showSaved, setShowSaved] = useState(false); let [showSaved, setShowSaved] = useState(false);
let [isPublic, setIsPublic] = useState(initialIsPublic); let [isPublic, setIsPublic] = useState(initialIsPublic);
const newCharacterUrl = () => `${window.location.origin}/1e/karakter/${newId}`
const handleSaveModalCopyAndClose = async () => {
await navigator.clipboard.writeText(newCharacterUrl());
handleSaveModalClose()
}
const handleSaveModalClose = () => {
setShowSaveModal(false);
navigate(`/1e/karakter/${newId}`)
}
const hideSaved = () => setShowSaved(false); const hideSaved = () => setShowSaved(false);
const onSaveClicked = async () => { const onSaveClicked = async () => {
faro?.api.pushEvent('character_stored', { faro?.api.pushEvent('character_stored', {
@@ -78,9 +97,9 @@ function CreateCharacterPage(props: {
is_public: isPublic.toString(), is_public: isPublic.toString(),
}) })
if (id == null) { if (id == null) {
let newId = await StoreNewCharacter(karakter, isPublic); let recievedId = await StoreNewCharacter(karakter, isPublic);
setShowSaved(true); setNewId(recievedId)
navigate(`/1e/karakter/${newId}`) setShowSaveModal(true);
} else { } else {
await UpdateCharacter(id, karakter, isPublic); await UpdateCharacter(id, karakter, isPublic);
setShowSaved(true); setShowSaved(true);
@@ -97,9 +116,31 @@ function CreateCharacterPage(props: {
</div> </div>
<ToastContainer className="position-fixed" position="top-end"> <ToastContainer className="position-fixed" position="top-end">
<Toast show={showSaved} onClose={hideSaved} bg="success"> <Toast show={showSaved} onClose={hideSaved} bg="success">
<Toast.Header><strong>Karakter mentve!</strong></Toast.Header> <Toast.Body className="text-light">Karakter mentve!</Toast.Body>
</Toast> </Toast>
</ToastContainer> </ToastContainer>
<Modal show={showSaveModal} onHide={handleSaveModalClose}>
<Modal.Header closeButton>
<Modal.Title>Karakter mentve!</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>Karaktered az alábbi {isPublic ? 'publikus' : 'privát'} URLen érhető el.</p>
<p><a href={newCharacterUrl()}>{newCharacterUrl()}</a></p>
<InputGroup className="mb-3">
<Form.Control id="input" value={newCharacterUrl()} />
<Button variant={"outline-dark"} onClick={() => {
let copyText = document.querySelector("#input") as any;
copyText?.select()
document.execCommand("copy");
}}>Másolás</Button>
</InputGroup>
</Modal.Body>
<Modal.Footer>
<Button variant="danger" onClick={handleSaveModalCopyAndClose}>
Másolás és bezárás
</Button>
</Modal.Footer>
</Modal>
<div className='p-3'> <div className='p-3'>
<form onSubmit={async (event) => event.preventDefault()}> <form onSubmit={async (event) => event.preventDefault()}>
<div className='row'> <div className='row'>
+158
View File
@@ -8,6 +8,16 @@
"resolved": "8.0.0", "resolved": "8.0.0",
"contentHash": "+MtOHPctq1QT1c03h+7g4oBWtZ/buQYUJg4AR0DG+qjmD2cQRMGWXC1J6/ITeCc6xa5BcXzJmt1L/8pVXIB4kw==" "contentHash": "+MtOHPctq1QT1c03h+7g4oBWtZ/buQYUJg4AR0DG+qjmD2cQRMGWXC1J6/ITeCc6xa5BcXzJmt1L/8pVXIB4kw=="
}, },
"Grpc.Core": {
"type": "Direct",
"requested": "[2.46.6, )",
"resolved": "2.46.6",
"contentHash": "ZoRg3KmOJ2urTF4+u3H0b1Yv10xzz2Y/flFWS2tnRmj8dbKLeiJaSRqu4LOBD3ova90evqLkVZ85kUkC4JT4lw==",
"dependencies": {
"Grpc.Core.Api": "2.46.6",
"System.Memory": "4.5.3"
}
},
"Microsoft.AspNetCore.Authentication.Facebook": { "Microsoft.AspNetCore.Authentication.Facebook": {
"type": "Direct", "type": "Direct",
"requested": "[8.0.0, )", "requested": "[8.0.0, )",
@@ -124,6 +134,78 @@
"Npgsql.EntityFrameworkCore.PostgreSQL": "1.1.0" "Npgsql.EntityFrameworkCore.PostgreSQL": "1.1.0"
} }
}, },
"OpenTelemetry.Exporter.Console": {
"type": "Direct",
"requested": "[1.7.0, )",
"resolved": "1.7.0",
"contentHash": "9mcwpArzG7+5cLnG6marWdVD1TyoVR03WAjShvxADqgsEeuzLMClTlgXi41bTCAgxjYyiHV5l60fJwXTekiJdQ==",
"dependencies": {
"OpenTelemetry": "1.7.0",
"System.Text.Encodings.Web": "4.7.2",
"System.Text.Json": "4.7.2"
}
},
"OpenTelemetry.Exporter.OpenTelemetryProtocol": {
"type": "Direct",
"requested": "[1.7.0, )",
"resolved": "1.7.0",
"contentHash": "ULGTxg4HdnJD+CIuiD15Uov4xVVqwpbNGFd075J3MT3lLM9XcwU4YRz7CCNmqIlehYaiZrGhUurXrI2LgZZL1Q==",
"dependencies": {
"Google.Protobuf": "[3.22.5, 4.0.0)",
"Grpc.Net.Client": "[2.52.0, 3.0.0)",
"OpenTelemetry": "1.7.0"
}
},
"OpenTelemetry.Extensions.Hosting": {
"type": "Direct",
"requested": "[1.7.0, )",
"resolved": "1.7.0",
"contentHash": "MbB7CWWqb7xHK0jTF9Gtvw/eLWdaKqzkE1XAwLe05xyskHuwJWAbZFax4nGLA71YkMWQNO5iPIBlirvYXOLMlg==",
"dependencies": {
"Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
"Microsoft.Extensions.Hosting.Abstractions": "8.0.0",
"OpenTelemetry": "1.7.0"
}
},
"OpenTelemetry.Instrumentation.AspNetCore": {
"type": "Direct",
"requested": "[1.7.0, )",
"resolved": "1.7.0",
"contentHash": "K/mjCmuR9zgrL6fMC6sbnX/y6BOJJFI3hp42O+tz8nT/w6sxbfjrLcU+fVwfct3lsnohSKdPfrq6fSrxAF5ezw==",
"dependencies": {
"OpenTelemetry.Api.ProviderBuilderExtensions": "1.7.0"
}
},
"Google.Protobuf": {
"type": "Transitive",
"resolved": "3.22.5",
"contentHash": "tTMtDZPbLxJew8pk7NBdqhLqC4OipfkZdwPuCEUNr2AoDo1siUGcxFqJK0wDewTL8ge5Cjrb16CToMPxBUHMGA=="
},
"Grpc.Core.Api": {
"type": "Transitive",
"resolved": "2.52.0",
"contentHash": "SQiPyBczG4vKPmI6Fd+O58GcxxDSFr6nfRAJuBDUNj+PgdokhjWJvZE/La1c09AkL2FVm/jrDloG89nkzmVF7A==",
"dependencies": {
"System.Memory": "4.5.3"
}
},
"Grpc.Net.Client": {
"type": "Transitive",
"resolved": "2.52.0",
"contentHash": "hWVH9g/Nnjz40ni//2S8UIOyEmhueQREoZIkD0zKHEPqLxXcNlbp4eebXIOicZtkwDSx0TFz9NpkbecEDn6rBw==",
"dependencies": {
"Grpc.Net.Common": "2.52.0",
"Microsoft.Extensions.Logging.Abstractions": "3.0.3"
}
},
"Grpc.Net.Common": {
"type": "Transitive",
"resolved": "2.52.0",
"contentHash": "di9qzpdx525IxumZdYmu6sG2y/gXJyYeZ1ruFUzB9BJ1nj4kU1/dTAioNCMt1VLRvNVDqh8S8B1oBdKhHJ4xRg==",
"dependencies": {
"Grpc.Core.Api": "2.52.0"
}
},
"Humanizer.Core": { "Humanizer.Core": {
"type": "Transitive", "type": "Transitive",
"resolved": "2.14.1", "resolved": "2.14.1",
@@ -265,6 +347,15 @@
"Microsoft.Extensions.Primitives": "8.0.0" "Microsoft.Extensions.Primitives": "8.0.0"
} }
}, },
"Microsoft.Extensions.Configuration": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
"Microsoft.Extensions.Primitives": "8.0.0"
}
},
"Microsoft.Extensions.Configuration.Abstractions": { "Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.0", "resolved": "8.0.0",
@@ -273,6 +364,14 @@
"Microsoft.Extensions.Primitives": "8.0.0" "Microsoft.Extensions.Primitives": "8.0.0"
} }
}, },
"Microsoft.Extensions.Configuration.Binder": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "mBMoXLsr5s1y2zOHWmKsE9veDcx8h1x/c3rz4baEdQKTeDcmQAPNbB54Pi/lhFO3K431eEq6PFbMgLaa6PHFfA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0"
}
},
"Microsoft.Extensions.DependencyInjection": { "Microsoft.Extensions.DependencyInjection": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.0", "resolved": "8.0.0",
@@ -371,6 +470,21 @@
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
} }
}, },
"Microsoft.Extensions.Logging.Configuration": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "ixXXV0G/12g6MXK65TLngYN9V5hQQRuV+fZi882WIoVJT7h5JvoYoxTEwCgdqwLjSneqh1O+66gM8sMr9z/rsQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "8.0.0",
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
"Microsoft.Extensions.Configuration.Binder": "8.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
"Microsoft.Extensions.Logging": "8.0.0",
"Microsoft.Extensions.Logging.Abstractions": "8.0.0",
"Microsoft.Extensions.Options": "8.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
}
},
"Microsoft.Extensions.Options": { "Microsoft.Extensions.Options": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.0", "resolved": "8.0.0",
@@ -380,6 +494,18 @@
"Microsoft.Extensions.Primitives": "8.0.0" "Microsoft.Extensions.Primitives": "8.0.0"
} }
}, },
"Microsoft.Extensions.Options.ConfigurationExtensions": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "0f4DMRqEd50zQh+UyJc+/HiBsZ3vhAQALgdkcQEalSH1L2isdC7Yj54M3cyo5e+BeO5fcBQ7Dxly8XiBBcvRgw==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
"Microsoft.Extensions.Configuration.Binder": "8.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
"Microsoft.Extensions.Options": "8.0.0",
"Microsoft.Extensions.Primitives": "8.0.0"
}
},
"Microsoft.Extensions.Primitives": { "Microsoft.Extensions.Primitives": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.0", "resolved": "8.0.0",
@@ -472,6 +598,33 @@
"Microsoft.Extensions.Logging.Abstractions": "8.0.0" "Microsoft.Extensions.Logging.Abstractions": "8.0.0"
} }
}, },
"OpenTelemetry": {
"type": "Transitive",
"resolved": "1.7.0",
"contentHash": "HNmOJg++4FtEJGCIn1dCJcDkHRLNuLKU047owrGXUOfz/C/c5oZHOPKrowKVOy2jOOh/F9+HDshzeOk5NnQEZg==",
"dependencies": {
"Microsoft.Extensions.Logging": "8.0.0",
"Microsoft.Extensions.Logging.Configuration": "8.0.0",
"OpenTelemetry.Api.ProviderBuilderExtensions": "1.7.0"
}
},
"OpenTelemetry.Api": {
"type": "Transitive",
"resolved": "1.7.0",
"contentHash": "w5uDHl1Nm7R5igWu1QjewpdPzJSavua8NTI3+iThOdRNHD3cabox8JeIJ8LpBSXGHARSNFMJZ/Xr5EGRinMTMg==",
"dependencies": {
"System.Diagnostics.DiagnosticSource": "8.0.0"
}
},
"OpenTelemetry.Api.ProviderBuilderExtensions": {
"type": "Transitive",
"resolved": "1.7.0",
"contentHash": "fHLmJcRJk1dAwddjBgvqi/Grmr04hPo1DoFwTa6hxtSvAFOXPU56Xe9Sh2VXqz6Gstzp6TCju8z0Sob1t7BzSg==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
"OpenTelemetry.Api": "1.7.0"
}
},
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.3.0", "resolved": "4.3.0",
@@ -887,6 +1040,11 @@
"System.Threading": "4.3.0" "System.Threading": "4.3.0"
} }
}, },
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.3",
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA=="
},
"System.Net.Http": { "System.Net.Http": {
"type": "Transitive", "type": "Transitive",
"resolved": "4.3.0", "resolved": "4.3.0",