Skip to content

Commit 159f92d

Browse files
nikolajlauridsennikolajlauridsen
andauthored
V8: Fix missing site identifier (#12035)
* Add SiteIdentifierService * Use SiteIdentifier service to create site identifier if it doesn't exist * Use default timeout for telemetry request * Use SiteIdentifierService in TelemetryIdentifierStep * Send SiteId when requesting dashboard * Make empty GUID an invalid site identifier Co-authored-by: nikolajlauridsen <[email protected]>
1 parent 96349e4 commit 159f92d

File tree

10 files changed

+167
-75
lines changed

10 files changed

+167
-75
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
3+
namespace Umbraco.Core.Telemetry
4+
{
5+
/// <summary>
6+
/// Used to get and create the site identifier
7+
/// </summary>
8+
public interface ISiteIdentifierService
9+
{
10+
11+
/// <summary>
12+
/// Tries to get the site identifier
13+
/// </summary>
14+
/// <returns></returns>
15+
bool TryGetSiteIdentifier(out Guid siteIdentifier);
16+
17+
/// <summary>
18+
/// Tries to get the site identifier or otherwise create it if it doesn't exist.
19+
/// </summary>
20+
/// <param name="siteIdentifier"></param>
21+
/// <returns></returns>
22+
bool TryGetOrCreateSiteIdentifier(out Guid siteIdentifier);
23+
24+
/// <summary>
25+
/// Creates the site identifier and writes it to config.
26+
/// </summary>
27+
bool TryCreateSiteIdentifier(out Guid createdGuid);
28+
}
29+
}

src/Umbraco.Core/Telemetry/TelemetryService.cs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using Umbraco.Core.Configuration;
4-
using Umbraco.Core.Configuration.UmbracoSettings;
54
using Umbraco.Core.Manifest;
65
using Umbraco.Core.Telemetry.Models;
76

@@ -10,24 +9,24 @@ namespace Umbraco.Core.Telemetry
109
/// <inheritdoc/>
1110
internal class TelemetryService : ITelemetryService
1211
{
13-
private readonly IUmbracoSettingsSection _settings;
12+
private readonly ISiteIdentifierService _siteIdentifierService;
1413
private readonly ManifestParser _manifestParser;
1514

1615
/// <summary>
1716
/// Initializes a new instance of the <see cref="TelemetryService"/> class.
1817
/// </summary>
1918
public TelemetryService(
2019
ManifestParser manifestParser,
21-
IUmbracoSettingsSection settings)
20+
ISiteIdentifierService siteIdentifierService)
2221
{
2322
_manifestParser = manifestParser;
24-
_settings = settings;
23+
_siteIdentifierService = siteIdentifierService;
2524
}
2625

2726
/// <inheritdoc/>
2827
public bool TryGetTelemetryReportData(out TelemetryReportData telemetryReportData)
2928
{
30-
if (TryGetTelemetryId(out Guid telemetryId) is false)
29+
if (_siteIdentifierService.TryGetOrCreateSiteIdentifier(out Guid telemetryId) is false)
3130
{
3231
telemetryReportData = null;
3332
return false;
@@ -42,20 +41,6 @@ public bool TryGetTelemetryReportData(out TelemetryReportData telemetryReportDat
4241
return true;
4342
}
4443

45-
private bool TryGetTelemetryId(out Guid telemetryId)
46-
{
47-
// Parse telemetry string as a GUID & verify its a GUID and not some random string
48-
// since users may have messed with or decided to empty the app setting or put in something random
49-
if (Guid.TryParse(_settings.BackOffice.Id, out var parsedTelemetryId) is false)
50-
{
51-
telemetryId = Guid.Empty;
52-
return false;
53-
}
54-
55-
telemetryId = parsedTelemetryId;
56-
return true;
57-
}
58-
5944
private IEnumerable<PackageTelemetry> GetPackageTelemetry()
6045
{
6146
List<PackageTelemetry> packages = new ();

src/Umbraco.Core/Umbraco.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@
400400
<Compile Include="Services\DateTypeServiceExtensions.cs" />
401401
<Compile Include="Services\PropertyValidationService.cs" />
402402
<Compile Include="Composing\TypeCollectionBuilderBase.cs" />
403+
<Compile Include="Telemetry\ISiteIdentifierService.cs" />
403404
<Compile Include="Telemetry\ITelemetryService.cs" />
404405
<Compile Include="Telemetry\Models\PackageTelemetry.cs" />
405406
<Compile Include="Telemetry\Models\TelemetryReportData.cs" />

src/Umbraco.Web/Editors/DashboardController.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using Umbraco.Core.Models;
2121
using Umbraco.Web.Services;
2222
using System.Web.Http;
23+
using Umbraco.Core.Telemetry;
2324

2425
namespace Umbraco.Web.Editors
2526
{
@@ -34,18 +35,28 @@ public class DashboardController : UmbracoApiController
3435
{
3536
private readonly IDashboardService _dashboardService;
3637
private readonly IContentDashboardSettings _dashboardSettings;
38+
private readonly ISiteIdentifierService _siteIdentifierService;
3739

3840
/// <summary>
3941
/// Initializes a new instance of the <see cref="DashboardController"/> with all its dependencies.
4042
/// </summary>
41-
public DashboardController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor,
42-
ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger,
43-
IRuntimeState runtimeState, IDashboardService dashboardService, UmbracoHelper umbracoHelper,
44-
IContentDashboardSettings dashboardSettings)
43+
public DashboardController(
44+
IGlobalSettings globalSettings,
45+
IUmbracoContextAccessor umbracoContextAccessor,
46+
ISqlContext sqlContext,
47+
ServiceContext services,
48+
AppCaches appCaches,
49+
IProfilingLogger logger,
50+
IRuntimeState runtimeState,
51+
IDashboardService dashboardService,
52+
UmbracoHelper umbracoHelper,
53+
IContentDashboardSettings dashboardSettings,
54+
ISiteIdentifierService siteIdentifierService)
4555
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
4656
{
4757
_dashboardService = dashboardService;
4858
_dashboardSettings = dashboardSettings;
59+
_siteIdentifierService = siteIdentifierService;
4960
}
5061

5162
//we have just one instance of HttpClient shared for the entire application
@@ -60,17 +71,19 @@ public async Task<JObject> GetRemoteDashboardContent(string section, string base
6071
var language = user.Language;
6172
var version = UmbracoVersion.SemanticVersion.ToSemanticString();
6273
var isAdmin = user.IsAdmin();
74+
_siteIdentifierService.TryGetOrCreateSiteIdentifier(out var siteIdentifier);
6375

6476
VerifyDashboardSource(baseUrl);
6577

66-
var url = string.Format("{0}{1}?section={2}&allowed={3}&lang={4}&version={5}&admin={6}",
78+
var url = string.Format("{0}{1}?section={2}&allowed={3}&lang={4}&version={5}&admin={6}&siteid={7}",
6779
baseUrl,
6880
_dashboardSettings.ContentDashboardPath,
6981
section,
7082
allowedSections,
7183
language,
7284
version,
73-
isAdmin);
85+
isAdmin,
86+
siteIdentifier.ToString());
7487
var key = "umbraco-dynamic-dashboard-" + language + allowedSections.Replace(",", "-") + section;
7588

7689
var content = AppCaches.RuntimeCache.GetCacheItem<JObject>(key);

src/Umbraco.Web/Install/InstallSteps/TelemetryIdentifierStep.cs

Lines changed: 8 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
using System;
2-
using System.IO;
3-
using System.Threading.Tasks;
4-
using System.Xml.Linq;
1+
using System.Threading.Tasks;
52
using Umbraco.Core.Configuration.UmbracoSettings;
6-
using Umbraco.Core.IO;
7-
using Umbraco.Core.Logging;
3+
using Umbraco.Core.Telemetry;
84
using Umbraco.Web.Install.Models;
95

106
namespace Umbraco.Web.Install.InstallSteps
@@ -14,54 +10,20 @@ namespace Umbraco.Web.Install.InstallSteps
1410
PerformsAppRestart = false)]
1511
internal class TelemetryIdentifierStep : InstallSetupStep<object>
1612
{
17-
private readonly IProfilingLogger _logger;
1813
private readonly IUmbracoSettingsSection _settings;
14+
private readonly ISiteIdentifierService _siteIdentifierService;
1915

20-
public TelemetryIdentifierStep(IProfilingLogger logger, IUmbracoSettingsSection settings)
16+
public TelemetryIdentifierStep(
17+
IUmbracoSettingsSection settings,
18+
ISiteIdentifierService siteIdentifierService)
2119
{
22-
_logger = logger;
2320
_settings = settings;
21+
_siteIdentifierService = siteIdentifierService;
2422
}
2523

2624
public override Task<InstallSetupResult> ExecuteAsync(object model)
2725
{
28-
// Generate GUID
29-
var telemetrySiteIdentifier = Guid.NewGuid();
30-
31-
// Modify the XML to add a new GUID site identifier
32-
// hack: ensure this does not trigger a restart
33-
using (ChangesMonitor.Suspended())
34-
{
35-
var umbracoSettingsPath = IOHelper.MapPath(SystemFiles.UmbracoSettings);
36-
if(File.Exists(umbracoSettingsPath) == false)
37-
{
38-
// Log an error
39-
_logger.Error<TelemetryIdentifierStep>("Unable to find umbracoSettings.config file to add telemetry site identifier");
40-
return Task.FromResult<InstallSetupResult>(null);
41-
}
42-
43-
try
44-
{
45-
var umbracoConfigXml = XDocument.Load(umbracoSettingsPath, LoadOptions.PreserveWhitespace);
46-
if (umbracoConfigXml.Root != null)
47-
{
48-
var backofficeElement = umbracoConfigXml.Root.Element("backOffice");
49-
if (backofficeElement == null)
50-
return Task.FromResult<InstallSetupResult>(null);
51-
52-
// Will add ID attribute if it does not exist
53-
backofficeElement.SetAttributeValue("id", telemetrySiteIdentifier.ToString());
54-
55-
// Save file back down
56-
umbracoConfigXml.Save(umbracoSettingsPath, SaveOptions.DisableFormatting);
57-
}
58-
}
59-
catch (Exception ex)
60-
{
61-
_logger.Error<TelemetryIdentifierStep>(ex, "Couldn't update umbracoSettings.config with a backoffice with a telemetry site identifier");
62-
}
63-
}
64-
26+
_siteIdentifierService.TryCreateSiteIdentifier(out _);
6527
return Task.FromResult<InstallSetupResult>(null);
6628
}
6729

src/Umbraco.Web/Runtime/WebInitialComposer.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@
3939
using Current = Umbraco.Web.Composing.Current;
4040
using Umbraco.Web.PropertyEditors;
4141
using Umbraco.Core.Models;
42+
using Umbraco.Core.Telemetry;
4243
using Umbraco.Web.Models;
44+
using Umbraco.Web.Telemetry;
4345

4446
namespace Umbraco.Web.Runtime
4547
{
@@ -58,6 +60,8 @@ public override void Compose(Composition composition)
5860

5961
composition.ComposeWebMappingProfiles();
6062

63+
composition.RegisterUnique<ISiteIdentifierService, SiteIdentifierService>();
64+
6165
//register the install components
6266
//NOTE: i tried to not have these registered if we weren't installing or upgrading but post install when the site restarts
6367
//it still needs to use the install controller so we can't do that

src/Umbraco.Web/Telemetry/ReportSiteTask.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,6 @@ public override async Task<bool> PerformRunAsync(CancellationToken token)
6262
{
6363
request.Content = new StringContent(JsonConvert.SerializeObject(telemetryReportData), Encoding.UTF8, "application/json"); //CONTENT-TYPE header
6464

65-
// Set a low timeout - no need to use a larger default timeout for this POST request
66-
_httpClient.Timeout = new TimeSpan(0, 0, 1);
67-
6865
// Make a HTTP Post to telemetry service
6966
// https://telemetry.umbraco.com/installs/
7067
// Fire & Forget, do not need to know if its a 200, 500 etc
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using System;
2+
using System.IO;
3+
using System.Xml.Linq;
4+
using Umbraco.Core.Configuration.UmbracoSettings;
5+
using Umbraco.Core.IO;
6+
using Umbraco.Core.Logging;
7+
using Umbraco.Core.Telemetry;
8+
using Umbraco.Web.Install;
9+
10+
namespace Umbraco.Web.Telemetry
11+
{
12+
internal class SiteIdentifierService : ISiteIdentifierService
13+
{
14+
private readonly IUmbracoSettingsSection _settings;
15+
private readonly ILogger _logger;
16+
17+
public SiteIdentifierService(IUmbracoSettingsSection settings, ILogger logger)
18+
{
19+
_settings = settings;
20+
_logger = logger;
21+
}
22+
23+
public bool TryGetSiteIdentifier(out Guid siteIdentifier)
24+
{
25+
// Parse telemetry string as a GUID & verify its a GUID and not some random string
26+
// since users may have messed with or decided to empty the app setting or put in something random
27+
if (Guid.TryParse(_settings.BackOffice.Id, out var parsedTelemetryId) is false
28+
|| parsedTelemetryId == Guid.Empty)
29+
{
30+
siteIdentifier = Guid.Empty;
31+
return false;
32+
}
33+
34+
siteIdentifier = parsedTelemetryId;
35+
return true;
36+
}
37+
38+
public bool TryGetOrCreateSiteIdentifier(out Guid siteIdentifier)
39+
{
40+
if (TryGetSiteIdentifier(out var existingId))
41+
{
42+
siteIdentifier = existingId;
43+
return true;
44+
}
45+
46+
if (TryCreateSiteIdentifier(out var createdId))
47+
{
48+
siteIdentifier = createdId;
49+
return true;
50+
}
51+
52+
siteIdentifier = Guid.Empty;
53+
return false;
54+
}
55+
56+
public bool TryCreateSiteIdentifier(out Guid createdGuid)
57+
{
58+
createdGuid = Guid.NewGuid();
59+
60+
// Modify the XML to add a new GUID site identifier
61+
// hack: ensure this does not trigger a restart
62+
using (ChangesMonitor.Suspended())
63+
{
64+
var umbracoSettingsPath = IOHelper.MapPath(SystemFiles.UmbracoSettings);
65+
66+
if (File.Exists(umbracoSettingsPath) is false)
67+
{
68+
_logger.Error<SiteIdentifierService>("Unable to find umbracoSettings.config file to add telemetry site identifier");
69+
return false;
70+
}
71+
72+
try
73+
{
74+
var umbracoConfigXml = XDocument.Load(umbracoSettingsPath, LoadOptions.PreserveWhitespace);
75+
if (umbracoConfigXml.Root != null)
76+
{
77+
var backofficeElement = umbracoConfigXml.Root.Element("backOffice");
78+
if (backofficeElement is null)
79+
{
80+
return false;
81+
}
82+
83+
// Will add ID attribute if it does not exist
84+
backofficeElement.SetAttributeValue("id", createdGuid.ToString());
85+
86+
// Save file back down
87+
umbracoConfigXml.Save(umbracoSettingsPath, SaveOptions.DisableFormatting);
88+
}
89+
}
90+
catch (Exception ex)
91+
{
92+
_logger.Error<SiteIdentifierService>(ex, "Couldn't update umbracoSettings.config with a backoffice with a telemetry site identifier");
93+
return false;
94+
}
95+
}
96+
97+
return true;
98+
}
99+
}
100+
}

src/Umbraco.Web/Telemetry/TelemetryComponent.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class TelemetryComponent : IComponent
1212
private readonly ITelemetryService _telemetryService;
1313
private BackgroundTaskRunner<IBackgroundTask> _telemetryReporterRunner;
1414

15-
public TelemetryComponent(IProfilingLogger logger, IUmbracoSettingsSection settings, ITelemetryService telemetryService)
15+
public TelemetryComponent(IProfilingLogger logger, ITelemetryService telemetryService)
1616
{
1717
_logger = logger;
1818
_telemetryService = telemetryService;

src/Umbraco.Web/Umbraco.Web.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@
347347
<Compile Include="Models\LinkType.cs" />
348348
<Compile Include="Models\TemplateQuery\OperatorFactory.cs" />
349349
<Compile Include="Telemetry\ReportSiteTask.cs" />
350+
<Compile Include="Telemetry\SiteIdentifierService.cs" />
350351
<Compile Include="Telemetry\TelemetryComponent.cs" />
351352
<Compile Include="Telemetry\TelemetryComposer.cs" />
352353
<Compile Include="Templates\HtmlLocalLinkParser.cs" />

0 commit comments

Comments
 (0)