From 2045f946a5340f3192fe4df89fb4d2211fe993c9 Mon Sep 17 00:00:00 2001 From: Roy Hagland Date: Wed, 22 Jul 2026 11:40:48 +0200 Subject: [PATCH 1/9] Add support for third-party DNS App repositories Adds an opt-in "Third Party" sub-tab under Apps for browsing and installing DNS apps from admin-added repository URLs, alongside the existing official DNS App Store. A repository is a JSON manifest in the same schema the official store already uses. - DnsApplicationManager: persists repository URLs to a new appRepositories.config file, fetches/caches each repo independently with per-repo error isolation (one bad repo can't break the list) - New endpoints: apps/repositories/list, apps/repositories/add, apps/repositories/remove - Existing Apps tab, official store, and install/update/uninstall endpoints are unchanged --- .../Dns/Applications/DnsApplicationManager.cs | 173 +++++++++++ DnsServerCore/DnsWebService.cs | 3 + DnsServerCore/WebServiceAppsApi.cs | 159 ++++++++++ DnsServerCore/www/index.html | 86 ++++-- DnsServerCore/www/js/apps.js | 275 ++++++++++++++++++ 5 files changed, 676 insertions(+), 20 deletions(-) diff --git a/DnsServerCore/Dns/Applications/DnsApplicationManager.cs b/DnsServerCore/Dns/Applications/DnsApplicationManager.cs index 97050779..a35e5a4d 100644 --- a/DnsServerCore/Dns/Applications/DnsApplicationManager.cs +++ b/DnsServerCore/Dns/Applications/DnsApplicationManager.cs @@ -60,6 +60,18 @@ public sealed class DnsApplicationManager : IDisposable const int APP_UPDATE_TIMER_INITIAL_INTERVAL = 10000; const int APP_UPDATE_TIMER_PERIODIC_INTERVAL = 86400000; + readonly string _customRepositoriesConfigFile; + readonly object _customRepositoriesLock = new object(); + List _customRepositoryUrls = new List(); + readonly ConcurrentDictionary _customRepositoryCache = new ConcurrentDictionary(); + + sealed class CustomRepositoryCacheEntry + { + public string JsonData; + public DateTime UpdatedOn; + public string LastError; + } + #endregion #region constructor @@ -72,6 +84,9 @@ public DnsApplicationManager(DnsServer dnsServer) if (!Directory.Exists(_appsPath)) Directory.CreateDirectory(_appsPath); + + _customRepositoriesConfigFile = Path.Combine(_dnsServer.ConfigFolder, "appRepositories.config"); + LoadCustomRepositoriesConfig(); } #endregion @@ -307,6 +322,94 @@ internal async Task GetStoreAppsJsonData() return _storeAppsJsonData; } + private void LoadCustomRepositoriesConfig() + { + if (!File.Exists(_customRepositoriesConfigFile)) + return; + + using (FileStream fS = new FileStream(_customRepositoriesConfigFile, FileMode.Open, FileAccess.Read)) + { + if (Encoding.ASCII.GetString(fS.ReadExactly(2)) != "AR") + throw new InvalidDataException("DNS Apps repositories config file format is invalid."); + + BinaryReader bR = new BinaryReader(fS); + + int version = bR.ReadByte(); + if (version > 1) + throw new InvalidDataException("DNS Apps repositories config version not supported."); + + int count = bR.ReadInt32(); + List repoUrls = new List(count); + + for (int i = 0; i < count; i++) + repoUrls.Add(fS.ReadShortString()); + + lock (_customRepositoriesLock) + { + _customRepositoryUrls = repoUrls; + } + } + } + + private void SaveCustomRepositoriesConfig() + { + //must be called with _customRepositoriesLock already held + string tmpFile = _customRepositoriesConfigFile + ".tmp"; + + using (FileStream fS = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite)) + { + fS.Write(Encoding.ASCII.GetBytes("AR")); + + BinaryWriter bW = new BinaryWriter(fS); + bW.Write((byte)1); //version + bW.Write(_customRepositoryUrls.Count); + + foreach (string repoUrl in _customRepositoryUrls) + fS.WriteShortString(repoUrl); + } + + File.Copy(tmpFile, _customRepositoriesConfigFile, true); + File.Delete(tmpFile); + } + + private async Task<(string jsonData, string error)> GetCustomRepositoryJsonDataAsync(string repoUrl) + { + if (_customRepositoryCache.TryGetValue(repoUrl, out CustomRepositoryCacheEntry cache) && (DateTime.UtcNow <= cache.UpdatedOn.AddSeconds(STORE_APPS_JSON_DATA_CACHE_TIME_SECONDS))) + return (cache.JsonData, cache.LastError); + + try + { + HttpClientNetworkHandler handler = new HttpClientNetworkHandler(); + handler.Proxy = _dnsServer.Proxy; + handler.NetworkType = HttpClientNetworkHandler.GetNetworkType(_dnsServer.IPv6Mode); + handler.DnsClient = _dnsServer; + + using (HttpClient http = new HttpClient(handler)) + { + string jsonData = await http.GetStringAsync(new Uri(repoUrl)); + + _customRepositoryCache[repoUrl] = new CustomRepositoryCacheEntry() { JsonData = jsonData, UpdatedOn = DateTime.UtcNow, LastError = null }; + + return (jsonData, null); + } + } + catch (Exception ex) + { + _dnsServer.LogManager.Write("DNS Server failed to fetch DNS App repository data from: " + repoUrl, ex); + + CustomRepositoryCacheEntry existing = _customRepositoryCache.AddOrUpdate(repoUrl, + new CustomRepositoryCacheEntry() { JsonData = null, UpdatedOn = DateTime.UtcNow, LastError = ex.Message }, + delegate (string key, CustomRepositoryCacheEntry old) + { + old.LastError = ex.Message; + old.UpdatedOn = DateTime.UtcNow; + return old; + }); + + return (existing.JsonData, existing.LastError); + } + } + #endregion #region public @@ -568,6 +671,76 @@ public async Task DownloadAndUpdateAppAsync(string applicationNa } } + public void AddCustomRepository(string repoUrl) + { + if (string.IsNullOrWhiteSpace(repoUrl)) + throw new DnsServerException("DNS App repository URL is required."); + + repoUrl = repoUrl.Trim(); + + if (!repoUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) + throw new DnsServerException("DNS App repository URL must start with 'https://'."); + + lock (_customRepositoriesLock) + { + foreach (string existingUrl in _customRepositoryUrls) + { + if (existingUrl.Equals(repoUrl, StringComparison.OrdinalIgnoreCase)) + throw new DnsServerException("DNS App repository already exists: " + repoUrl); + } + + List updated = new List(_customRepositoryUrls) { repoUrl }; + _customRepositoryUrls = updated; + + SaveCustomRepositoriesConfig(); + } + } + + public void RemoveCustomRepository(string repoUrl) + { + lock (_customRepositoriesLock) + { + int index = _customRepositoryUrls.FindIndex(delegate (string existingUrl) { return existingUrl.Equals(repoUrl, StringComparison.OrdinalIgnoreCase); }); + if (index < 0) + throw new DnsServerException("DNS App repository does not exist: " + repoUrl); + + List updated = new List(_customRepositoryUrls); + updated.RemoveAt(index); + _customRepositoryUrls = updated; + + SaveCustomRepositoriesConfig(); + } + + _customRepositoryCache.TryRemove(repoUrl, out _); + } + + public IReadOnlyList GetCustomRepositoryUrls() + { + lock (_customRepositoriesLock) + { + return _customRepositoryUrls; + } + } + + public async Task> GetCustomRepositoriesStoreAppsJsonDataAsync() + { + IReadOnlyList repoUrls = GetCustomRepositoryUrls(); + + Task<(string jsonData, string error)>[] tasks = new Task<(string, string)>[repoUrls.Count]; + + for (int i = 0; i < repoUrls.Count; i++) + tasks[i] = GetCustomRepositoryJsonDataAsync(repoUrls[i]); + + (string jsonData, string error)[] results = await Task.WhenAll(tasks); + + List<(string, string, string)> repoResults = new List<(string, string, string)>(repoUrls.Count); + + for (int i = 0; i < repoUrls.Count; i++) + repoResults.Add((repoUrls[i], results[i].jsonData, results[i].error)); + + return repoResults; + } + #endregion #region properties diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs index 7f5c5f3f..58ff8765 100644 --- a/DnsServerCore/DnsWebService.cs +++ b/DnsServerCore/DnsWebService.cs @@ -2185,6 +2185,9 @@ private void ConfigureWebServiceRoutes() _webService.MapGetAndPost("/api/apps/uninstall", _appsApi.UninstallApp); _webService.MapGetAndPost("/api/apps/config/get", _appsApi.GetAppConfigAsync); _webService.MapGetAndPost("/api/apps/config/set", _appsApi.SetAppConfigAsync); + _webService.MapGetAndPost("/api/apps/repositories/list", _appsApi.ListCustomRepositoryAppsAsync); + _webService.MapGetAndPost("/api/apps/repositories/add", _appsApi.AddAppRepository); + _webService.MapGetAndPost("/api/apps/repositories/remove", _appsApi.RemoveAppRepository); //dns client _webService.MapGetAndPost("/api/dnsClient/resolve", _api.ResolveQueryAsync); diff --git a/DnsServerCore/WebServiceAppsApi.cs b/DnsServerCore/WebServiceAppsApi.cs index 26f58b2d..20baeef3 100644 --- a/DnsServerCore/WebServiceAppsApi.cs +++ b/DnsServerCore/WebServiceAppsApi.cs @@ -276,6 +276,165 @@ public async Task ListStoreApps(HttpContext context) jsonWriter.WriteEndArray(); } + public async Task ListCustomRepositoryAppsAsync(HttpContext context) + { + User sessionUser = _dnsWebService.GetSessionUser(context); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, sessionUser, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + IReadOnlyList<(string repoUrl, string jsonData, string error)> repoResults = await _dnsWebService._dnsServer.DnsApplicationManager.GetCustomRepositoriesStoreAppsJsonDataAsync(); + + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + + //parse each repo's data upfront so a parse failure can be reported as the repo's error too, not just a fetch failure + Dictionary parsedRepoData = new Dictionary(); + Dictionary repoErrors = new Dictionary(); + + try + { + foreach ((string repoUrl, string jsonData, string fetchError) in repoResults) + { + if (fetchError is not null) + { + repoErrors[repoUrl] = fetchError; + continue; + } + + if (jsonData is null) + continue; //should not happen when fetchError is null, but guard anyway + + try + { + parsedRepoData[repoUrl] = JsonDocument.Parse(jsonData); + } + catch (Exception ex) + { + _dnsWebService._log.Write("DNS App repository returned invalid JSON data: " + repoUrl, ex); + repoErrors[repoUrl] = "Repository data is not valid JSON: " + ex.Message; + } + } + + jsonWriter.WritePropertyName("repositories"); + jsonWriter.WriteStartArray(); + + foreach ((string repoUrl, _, _) in repoResults) + { + jsonWriter.WriteStartObject(); + + jsonWriter.WriteString("url", repoUrl); + + if (repoErrors.TryGetValue(repoUrl, out string error)) + jsonWriter.WriteString("error", error); + + jsonWriter.WriteEndObject(); + } + + jsonWriter.WriteEndArray(); + + jsonWriter.WritePropertyName("storeApps"); + jsonWriter.WriteStartArray(); + + foreach (KeyValuePair parsedRepo in parsedRepoData) + { + string repoUrl = parsedRepo.Key; + + foreach (JsonElement jsonStoreApp in parsedRepo.Value.RootElement.EnumerateArray()) + { + string name = jsonStoreApp.GetProperty("name").GetString(); + string description = jsonStoreApp.GetProperty("description").GetString(); + string version = null; + string url = null; + string size = null; + Version storeAppVersion = null; + Version lastServerVersion = null; + + foreach (JsonElement jsonVersion in jsonStoreApp.GetProperty("versions").EnumerateArray()) + { + string strServerVersion = jsonVersion.GetProperty("serverVersion").GetString(); + Version requiredServerVersion = new Version(strServerVersion); + + if (_dnsWebService._currentVersion < requiredServerVersion) + continue; + + if ((lastServerVersion is not null) && (lastServerVersion > requiredServerVersion)) + continue; + + version = jsonVersion.GetProperty("version").GetString(); + url = jsonVersion.GetProperty("url").GetString(); + size = jsonVersion.GetProperty("size").GetString(); + + storeAppVersion = new Version(version); + lastServerVersion = requiredServerVersion; + } + + if (storeAppVersion is null) + continue; //app is not compatible with this server version + + jsonWriter.WriteStartObject(); + + jsonWriter.WriteString("name", name); + jsonWriter.WriteString("description", description); + jsonWriter.WriteString("version", version); + jsonWriter.WriteString("url", url); + jsonWriter.WriteString("size", size); + jsonWriter.WriteString("repository", repoUrl); + + bool installed = _dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication installedApp); + + jsonWriter.WriteBoolean("installed", installed); + + if (installed) + { + jsonWriter.WriteString("installedVersion", DnsWebService.GetCleanVersion(installedApp.Version)); + jsonWriter.WriteBoolean("updateAvailable", storeAppVersion > installedApp.Version); + } + + jsonWriter.WriteEndObject(); + } + } + } + finally + { + foreach (JsonDocument jsonDocument in parsedRepoData.Values) + jsonDocument.Dispose(); + } + + jsonWriter.WriteEndArray(); + } + + public void AddAppRepository(HttpContext context) + { + User sessionUser = _dnsWebService.GetSessionUser(context); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, sessionUser, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string url = request.GetQueryOrForm("url").Trim(); + + _dnsWebService._dnsServer.DnsApplicationManager.AddCustomRepository(url); + + _dnsWebService._log.Write(_dnsWebService.GetRemoteEndPoint(context), "[" + sessionUser.Username + "] DNS App repository was added: " + url); + } + + public void RemoveAppRepository(HttpContext context) + { + User sessionUser = _dnsWebService.GetSessionUser(context); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, sessionUser, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string url = request.GetQueryOrForm("url").Trim(); + + _dnsWebService._dnsServer.DnsApplicationManager.RemoveCustomRepository(url); + + _dnsWebService._log.Write(_dnsWebService.GetRemoteEndPoint(context), "[" + sessionUser.Username + "] DNS App repository was removed: " + url); + } + public async Task DownloadAndInstallAppAsync(HttpContext context) { User sessionUser = _dnsWebService.GetSessionUser(context); diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index 1678bf9e..246c5b7a 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -805,30 +805,76 @@

-
+ + +
+
+
+ +
+
+
+ + +
+
+
-
-
-
- - + + + + + + + + + + + + +
Installed Apps
Total Apps: 0
-
- - - - - - - - - - - - -
Installed Apps
Total Apps: 0
+
+
+ +
+ +

Add a third-party DNS App repository URL (a JSON manifest in the same format as the official DNS App Store) to browse and install apps from it. These apps are not maintained or vetted by Technitium.

+ +
+ + +
+ + + + +
+
+ + + +
+ + + + + + + + + + + + +
Third Party Apps
Total Apps: 0
+
+
diff --git a/DnsServerCore/www/js/apps.js b/DnsServerCore/www/js/apps.js index ee4b8042..315504b2 100644 --- a/DnsServerCore/www/js/apps.js +++ b/DnsServerCore/www/js/apps.js @@ -520,3 +520,278 @@ function saveAppConfig() { objAlertPlaceholder: divAppConfigAlert }); } + +//third party app repositories +// +//Note: unlike the official DNS App Store, this data comes from repository URLs +//added by the admin, so name/description/url/error values are not trusted +//content - always render them via htmlEncode(), never as raw inline JS string +//literals in onclick attributes. + +function refreshThirdPartyApps() { + var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); + var divThirdPartyAppsLoader = $("#divThirdPartyAppsLoader"); + var divThirdPartyApps = $("#divThirdPartyApps"); + + divThirdPartyApps.hide(); + divThirdPartyAppsLoader.show(); + + HTTPRequest({ + url: "api/apps/repositories/list", + token: sessionData.token, + success: function (responseJSON) { + var repositories = responseJSON.response.repositories; + var storeApps = responseJSON.response.storeApps; + + var repoHtmlRows = ""; + + for (var i = 0; i < repositories.length; i++) + repoHtmlRows += getThirdPartyRepoRowHtml(repositories[i]); + + if (repositories.length > 0) + $("#tableThirdPartyReposBody").html(repoHtmlRows); + else + $("#tableThirdPartyReposBody").html("No Repositories Added"); + + var tableHtmlRows = ""; + + for (var i = 0; i < storeApps.length; i++) + tableHtmlRows += getThirdPartyStoreAppRowHtml(storeApps[i]); + + $("#tableThirdPartyStoreAppsBody").html(tableHtmlRows); + + if (storeApps.length > 0) + $("#tableThirdPartyStoreAppsFooter").html("Total Apps: " + storeApps.length + ""); + else + $("#tableThirdPartyStoreAppsFooter").html("No Apps Found"); + + divThirdPartyAppsLoader.hide(); + divThirdPartyApps.show(); + }, + error: function () { + divThirdPartyAppsLoader.hide(); + divThirdPartyApps.show(); + }, + invalidToken: function () { + showPageLogin(); + }, + objAlertPlaceholder: divThirdPartyAppsAlert, + objLoaderPlaceholder: divThirdPartyAppsLoader + }); +} + +function getThirdPartyRepoRowId(url) { + return btoa(url).replace(/[^a-zA-Z0-9]/g, ""); +} + +function getThirdPartyRepoRowHtml(repo) { + var id = getThirdPartyRepoRowId(repo.url); + + var row = "
" + htmlEncode(repo.url) + "
"; + + if (repo.error != null) + row += "
Unreachable: " + htmlEncode(repo.error) + "
"; + + row += ""; + + return row; +} + +function addThirdPartyRepository() { + var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); + var txtThirdPartyRepoUrl = $("#txtThirdPartyRepoUrl"); + var url = txtThirdPartyRepoUrl.val(); + + if ((url === null) || (url === "")) { + showAlert("warning", "Missing!", "Please enter a DNS App repository URL.", divThirdPartyAppsAlert); + txtThirdPartyRepoUrl.trigger("focus"); + return; + } + + var btn = $("#btnThirdPartyRepoAdd"); + btn.button("loading"); + + HTTPRequest({ + url: "api/apps/repositories/add?url=" + encodeURIComponent(url), + token: sessionData.token, + success: function (responseJSON) { + btn.button("reset"); + txtThirdPartyRepoUrl.val(""); + + showAlert("success", "Repository Added!", "DNS App repository was added successfully.", divThirdPartyAppsAlert); + + refreshThirdPartyApps(); + }, + error: function () { + btn.button("reset"); + }, + invalidToken: function () { + showPageLogin(); + }, + objAlertPlaceholder: divThirdPartyAppsAlert + }); +} + +function removeThirdPartyRepository(objBtn) { + var btn = $(objBtn); + var url = btn.attr("data-url"); + + if (!confirm("Are you sure you want to remove the DNS App repository '" + url + "'?")) + return; + + var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); + + btn.button("loading"); + + HTTPRequest({ + url: "api/apps/repositories/remove?url=" + encodeURIComponent(url), + token: sessionData.token, + success: function (responseJSON) { + showAlert("success", "Repository Removed!", "DNS App repository was removed successfully.", divThirdPartyAppsAlert); + + refreshThirdPartyApps(); + }, + error: function () { + btn.button("reset"); + }, + invalidToken: function () { + showPageLogin(); + }, + objAlertPlaceholder: divThirdPartyAppsAlert + }); +} + +function getThirdPartyStoreAppRowHtml(app) { + var id = Math.floor(Math.random() * 1000000); + var name = app.name; + var version = app.version; + var description = app.description; + var url = app.url; + var size = app.size; + var repository = app.repository; + var installed = app.installed; + var installedVersion = app.installedVersion; + var updateAvailable = installed ? app.updateAvailable : false; + + var displayVersion = installed ? installedVersion : version; + + var row = "
" + htmlEncode(name) + "
"; + row += "Version " + htmlEncode(displayVersion) + " "; + row += "Update " + htmlEncode(version) + "
"; + row += "
" + htmlEncode(description).replace(/\n/g, "
") + "
"; + row += "
Repository: " + htmlEncode(repository) + "
App Zip File: " + htmlEncode(url) + "
Size: " + htmlEncode(size) + "
"; + + row += ""; + row += ""; + row += ""; + row += ""; + + return row; +} + +function installThirdPartyStoreApp(objBtn) { + var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); + var btn = $(objBtn); + var appName = btn.attr("data-name"); + var url = btn.attr("data-url"); + + btn.button("loading"); + + HTTPRequest({ + url: "api/apps/downloadAndInstall?name=" + encodeURIComponent(appName) + "&url=" + encodeURIComponent(url), + token: sessionData.token, + success: function (responseJSON) { + btn.button("reset"); + btn.hide(); + + var id = btn.attr("data-id"); + $("#btnThirdPartyStoreAppUninstall" + id).show(); + + var tableHtmlRow = getAppRowHtml(responseJSON.response.installedApp); + $("#tableAppsBody").prepend(tableHtmlRow); + updateAppsFooterCount(); + + showAlert("success", "App Installed!", "DNS application '" + appName + "' was installed successfully from the third-party repository.", divThirdPartyAppsAlert); + }, + error: function () { + btn.button("reset"); + }, + invalidToken: function () { + showPageLogin(); + }, + objAlertPlaceholder: divThirdPartyAppsAlert + }); +} + +function updateThirdPartyStoreApp(objBtn) { + var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); + var btn = $(objBtn); + var appName = btn.attr("data-name"); + var url = btn.attr("data-url"); + + btn.button("loading"); + + HTTPRequest({ + url: "api/apps/downloadAndUpdate?name=" + encodeURIComponent(appName) + "&url=" + encodeURIComponent(url), + token: sessionData.token, + success: function (responseJSON) { + btn.button("reset"); + btn.hide(); + + var id = btn.attr("data-id"); + $("#spanThirdPartyStoreAppUpdateVersion" + id).hide(); + $("#spanThirdPartyStoreAppDisplayVersion" + id).text($("#spanThirdPartyStoreAppUpdateVersion" + id).text().replace(/Update/g, "Version")); + + var tableHtmlRow = getAppRowHtml(responseJSON.response.updatedApp); + var appRowId = getAppRowId(responseJSON.response.updatedApp.name); + $("#trApp" + appRowId).replaceWith(tableHtmlRow); + + showAlert("success", "App Updated!", "DNS application '" + appName + "' was updated successfully from the third-party repository.", divThirdPartyAppsAlert); + }, + error: function () { + btn.button("reset"); + }, + invalidToken: function () { + showPageLogin(); + }, + objAlertPlaceholder: divThirdPartyAppsAlert + }); +} + +function uninstallThirdPartyStoreApp(objBtn) { + var btn = $(objBtn); + var appName = btn.attr("data-name"); + + if (!confirm("Are you sure you want to uninstall the DNS application '" + appName + "'?")) + return; + + var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); + + btn.button("loading"); + + HTTPRequest({ + url: "api/apps/uninstall?name=" + encodeURIComponent(appName), + token: sessionData.token, + success: function (responseJSON) { + btn.button("reset"); + btn.hide(); + + var id = btn.attr("data-id"); + $("#btnThirdPartyStoreAppInstall" + id).show(); + $("#btnThirdPartyStoreAppUpdate" + id).hide(); + + var appRowId = getAppRowId(appName); + $("#trApp" + appRowId).remove(); + updateAppsFooterCount(); + + showAlert("success", "App Uninstalled!", "DNS application '" + appName + "' was uninstalled successfully.", divThirdPartyAppsAlert); + }, + error: function () { + btn.button("reset"); + }, + invalidToken: function () { + showPageLogin(); + }, + objAlertPlaceholder: divThirdPartyAppsAlert + }); +} From 1f4c0d22075df60857a79f85326c72aaa714e291 Mon Sep 17 00:00:00 2001 From: Roy Hagland Date: Wed, 22 Jul 2026 11:41:23 +0200 Subject: [PATCH 2/9] Document third-party DNS App repository endpoints in APIDOCS.md --- APIDOCS.md | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/APIDOCS.md b/APIDOCS.md index 058f7511..bf1d2713 100644 --- a/APIDOCS.md +++ b/APIDOCS.md @@ -4689,6 +4689,104 @@ RESPONSE: } ``` +### List Third Party App Repository Apps + +Lists apps available from all configured third-party DNS App repositories. A repository is any HTTPS URL serving a JSON manifest in the same schema as the official DNS App Store. Each configured repository is fetched independently; if a repository is unreachable or returns invalid data, it is reported with an `error` and does not affect the other repositories' listings. + +URL:\ +`http://localhost:5380/api/apps/repositories/list` + +PERMISSIONS:\ +Apps: View + +HEADERS: +- Authorization: Bearer + +WHERE: +- `token`: The session token generated by the `login` or the `createToken` call. +- `node` (optional): The node domain name for which the this API call is intended. When unspecified, the current node is used. This parameter can be used only when Clustering is initialized. + +RESPONSE: +``` +{ + "response": { + "repositories": [ + { + "url": "https://example.com/store.json" + }, + { + "url": "https://example.org/store.json", + "error": "Response status code does not indicate success: 404 (Not Found)." + } + ], + "storeApps": [ + { + "name": "Example Third Party App", + "description": "An example app served from a third-party repository.", + "version": "1.0.0", + "url": "https://example.com/apps/ExampleApp.zip", + "size": "12.3 KB", + "repository": "https://example.com/store.json", + "installed": false + } + ] + }, + "status": "ok" +} +``` + +### Add App Repository + +Adds a third-party DNS App repository URL. The URL must serve a JSON manifest in the same schema as the official DNS App Store (an array of app entries, each with `name`, `description`, and `versions`). + +URL:\ +`http://localhost:5380/api/apps/repositories/add?url=https://example.com/store.json` + +PERMISSIONS:\ +Apps: Modify + +HEADERS: +- Authorization: Bearer + +WHERE: +- `token`: The session token generated by the `login` or the `createToken` call. +- `url`: The HTTPS URL of the DNS App repository's JSON manifest. +- `node` (optional): The node domain name for which the this API call is intended. When unspecified, the current node is used. This parameter can be used only when Clustering is initialized. + +RESPONSE: +``` +{ + "response": {}, + "status": "ok" +} +``` + +### Remove App Repository + +Removes a previously added third-party DNS App repository URL. This does not uninstall any apps already installed from that repository. + +URL:\ +`http://localhost:5380/api/apps/repositories/remove?url=https://example.com/store.json` + +PERMISSIONS:\ +Apps: Modify + +HEADERS: +- Authorization: Bearer + +WHERE: +- `token`: The session token generated by the `login` or the `createToken` call. +- `url`: The HTTPS URL of the DNS App repository's JSON manifest. +- `node` (optional): The node domain name for which the this API call is intended. When unspecified, the current node is used. This parameter can be used only when Clustering is initialized. + +RESPONSE: +``` +{ + "response": {}, + "status": "ok" +} +``` + ### Download And Install App Download an app zip file from given URL and installs it on the DNS Server. From 3c226b9ae9e0322ff7327f79158d3cccadaa9b4b Mon Sep 17 00:00:00 2001 From: Roy Hagland Date: Wed, 22 Jul 2026 11:52:18 +0200 Subject: [PATCH 3/9] Add repository display name and rename Third Party tab to Community Matches Synology Package Center's pattern: a repository is now added with a Name + URL pair (name optional, falls back to the URL) instead of a bare URL, so the UI can show a friendly label. Bumped the repo config file to format version 2, with a version-gated fallback to read pre-existing v1 (URL-only) entries. Renamed the "Third Party" tab/identifiers to "Community" throughout the frontend to match the Synology terminology this feature is modeled on. --- APIDOCS.md | 18 ++- .../Dns/Applications/DnsApplicationManager.cs | 92 +++++++---- DnsServerCore/WebServiceAppsApi.cs | 15 +- DnsServerCore/www/index.html | 27 ++-- DnsServerCore/www/js/apps.js | 143 ++++++++++-------- 5 files changed, 177 insertions(+), 118 deletions(-) diff --git a/APIDOCS.md b/APIDOCS.md index bf1d2713..0ef07212 100644 --- a/APIDOCS.md +++ b/APIDOCS.md @@ -4689,9 +4689,9 @@ RESPONSE: } ``` -### List Third Party App Repository Apps +### List Community App Repository Apps -Lists apps available from all configured third-party DNS App repositories. A repository is any HTTPS URL serving a JSON manifest in the same schema as the official DNS App Store. Each configured repository is fetched independently; if a repository is unreachable or returns invalid data, it is reported with an `error` and does not affect the other repositories' listings. +Lists apps available from all configured community (third-party) DNS App repositories. A repository is any HTTPS URL serving a JSON manifest in the same schema as the official DNS App Store. Each configured repository is fetched independently; if a repository is unreachable or returns invalid data, it is reported with an `error` and does not affect the other repositories' listings. URL:\ `http://localhost:5380/api/apps/repositories/list` @@ -4712,21 +4712,24 @@ RESPONSE: "response": { "repositories": [ { + "name": "Example Repository", "url": "https://example.com/store.json" }, { + "name": "Another Repository", "url": "https://example.org/store.json", "error": "Response status code does not indicate success: 404 (Not Found)." } ], "storeApps": [ { - "name": "Example Third Party App", - "description": "An example app served from a third-party repository.", + "name": "Example Community App", + "description": "An example app served from a community repository.", "version": "1.0.0", "url": "https://example.com/apps/ExampleApp.zip", "size": "12.3 KB", "repository": "https://example.com/store.json", + "repositoryName": "Example Repository", "installed": false } ] @@ -4737,10 +4740,10 @@ RESPONSE: ### Add App Repository -Adds a third-party DNS App repository URL. The URL must serve a JSON manifest in the same schema as the official DNS App Store (an array of app entries, each with `name`, `description`, and `versions`). +Adds a community (third-party) DNS App repository URL. The URL must serve a JSON manifest in the same schema as the official DNS App Store (an array of app entries, each with `name`, `description`, and `versions`). URL:\ -`http://localhost:5380/api/apps/repositories/add?url=https://example.com/store.json` +`http://localhost:5380/api/apps/repositories/add?name=Example%20Repository&url=https://example.com/store.json` PERMISSIONS:\ Apps: Modify @@ -4750,6 +4753,7 @@ HEADERS: WHERE: - `token`: The session token generated by the `login` or the `createToken` call. +- `name` (optional): A display name for the repository. When unspecified, the URL is used as the display name. - `url`: The HTTPS URL of the DNS App repository's JSON manifest. - `node` (optional): The node domain name for which the this API call is intended. When unspecified, the current node is used. This parameter can be used only when Clustering is initialized. @@ -4763,7 +4767,7 @@ RESPONSE: ### Remove App Repository -Removes a previously added third-party DNS App repository URL. This does not uninstall any apps already installed from that repository. +Removes a previously added community (third-party) DNS App repository URL. This does not uninstall any apps already installed from that repository. URL:\ `http://localhost:5380/api/apps/repositories/remove?url=https://example.com/store.json` diff --git a/DnsServerCore/Dns/Applications/DnsApplicationManager.cs b/DnsServerCore/Dns/Applications/DnsApplicationManager.cs index a35e5a4d..2c85bb8b 100644 --- a/DnsServerCore/Dns/Applications/DnsApplicationManager.cs +++ b/DnsServerCore/Dns/Applications/DnsApplicationManager.cs @@ -62,7 +62,7 @@ public sealed class DnsApplicationManager : IDisposable readonly string _customRepositoriesConfigFile; readonly object _customRepositoriesLock = new object(); - List _customRepositoryUrls = new List(); + List _customRepositories = new List(); readonly ConcurrentDictionary _customRepositoryCache = new ConcurrentDictionary(); sealed class CustomRepositoryCacheEntry @@ -74,6 +74,22 @@ sealed class CustomRepositoryCacheEntry #endregion + #region public types + + public readonly struct AppRepository + { + public readonly string Name; + public readonly string Url; + + public AppRepository(string name, string url) + { + Name = name; + Url = url; + } + } + + #endregion + #region constructor public DnsApplicationManager(DnsServer dnsServer) @@ -335,18 +351,32 @@ private void LoadCustomRepositoriesConfig() BinaryReader bR = new BinaryReader(fS); int version = bR.ReadByte(); - if (version > 1) + if (version > 2) throw new InvalidDataException("DNS Apps repositories config version not supported."); int count = bR.ReadInt32(); - List repoUrls = new List(count); + List repositories = new List(count); for (int i = 0; i < count; i++) - repoUrls.Add(fS.ReadShortString()); + { + if (version >= 2) + { + string name = fS.ReadShortString(); + string url = fS.ReadShortString(); + + repositories.Add(new AppRepository(name, url)); + } + else + { + string url = fS.ReadShortString(); + + repositories.Add(new AppRepository(url, url)); //v1 had no name; use URL as the display name + } + } lock (_customRepositoriesLock) { - _customRepositoryUrls = repoUrls; + _customRepositories = repositories; } } } @@ -361,11 +391,14 @@ private void SaveCustomRepositoriesConfig() fS.Write(Encoding.ASCII.GetBytes("AR")); BinaryWriter bW = new BinaryWriter(fS); - bW.Write((byte)1); //version - bW.Write(_customRepositoryUrls.Count); + bW.Write((byte)2); //version + bW.Write(_customRepositories.Count); - foreach (string repoUrl in _customRepositoryUrls) - fS.WriteShortString(repoUrl); + foreach (AppRepository repository in _customRepositories) + { + fS.WriteShortString(repository.Name); + fS.WriteShortString(repository.Url); + } } File.Copy(tmpFile, _customRepositoriesConfigFile, true); @@ -671,7 +704,7 @@ public async Task DownloadAndUpdateAppAsync(string applicationNa } } - public void AddCustomRepository(string repoUrl) + public void AddCustomRepository(string name, string repoUrl) { if (string.IsNullOrWhiteSpace(repoUrl)) throw new DnsServerException("DNS App repository URL is required."); @@ -681,16 +714,21 @@ public void AddCustomRepository(string repoUrl) if (!repoUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) throw new DnsServerException("DNS App repository URL must start with 'https://'."); + if (string.IsNullOrWhiteSpace(name)) + name = repoUrl; + else + name = name.Trim(); + lock (_customRepositoriesLock) { - foreach (string existingUrl in _customRepositoryUrls) + foreach (AppRepository existing in _customRepositories) { - if (existingUrl.Equals(repoUrl, StringComparison.OrdinalIgnoreCase)) + if (existing.Url.Equals(repoUrl, StringComparison.OrdinalIgnoreCase)) throw new DnsServerException("DNS App repository already exists: " + repoUrl); } - List updated = new List(_customRepositoryUrls) { repoUrl }; - _customRepositoryUrls = updated; + List updated = new List(_customRepositories) { new AppRepository(name, repoUrl) }; + _customRepositories = updated; SaveCustomRepositoriesConfig(); } @@ -700,13 +738,13 @@ public void RemoveCustomRepository(string repoUrl) { lock (_customRepositoriesLock) { - int index = _customRepositoryUrls.FindIndex(delegate (string existingUrl) { return existingUrl.Equals(repoUrl, StringComparison.OrdinalIgnoreCase); }); + int index = _customRepositories.FindIndex(delegate (AppRepository existing) { return existing.Url.Equals(repoUrl, StringComparison.OrdinalIgnoreCase); }); if (index < 0) throw new DnsServerException("DNS App repository does not exist: " + repoUrl); - List updated = new List(_customRepositoryUrls); + List updated = new List(_customRepositories); updated.RemoveAt(index); - _customRepositoryUrls = updated; + _customRepositories = updated; SaveCustomRepositoriesConfig(); } @@ -714,29 +752,29 @@ public void RemoveCustomRepository(string repoUrl) _customRepositoryCache.TryRemove(repoUrl, out _); } - public IReadOnlyList GetCustomRepositoryUrls() + public IReadOnlyList GetCustomRepositories() { lock (_customRepositoriesLock) { - return _customRepositoryUrls; + return _customRepositories; } } - public async Task> GetCustomRepositoriesStoreAppsJsonDataAsync() + public async Task> GetCustomRepositoriesStoreAppsJsonDataAsync() { - IReadOnlyList repoUrls = GetCustomRepositoryUrls(); + IReadOnlyList repositories = GetCustomRepositories(); - Task<(string jsonData, string error)>[] tasks = new Task<(string, string)>[repoUrls.Count]; + Task<(string jsonData, string error)>[] tasks = new Task<(string, string)>[repositories.Count]; - for (int i = 0; i < repoUrls.Count; i++) - tasks[i] = GetCustomRepositoryJsonDataAsync(repoUrls[i]); + for (int i = 0; i < repositories.Count; i++) + tasks[i] = GetCustomRepositoryJsonDataAsync(repositories[i].Url); (string jsonData, string error)[] results = await Task.WhenAll(tasks); - List<(string, string, string)> repoResults = new List<(string, string, string)>(repoUrls.Count); + List<(string, string, string, string)> repoResults = new List<(string, string, string, string)>(repositories.Count); - for (int i = 0; i < repoUrls.Count; i++) - repoResults.Add((repoUrls[i], results[i].jsonData, results[i].error)); + for (int i = 0; i < repositories.Count; i++) + repoResults.Add((repositories[i].Name, repositories[i].Url, results[i].jsonData, results[i].error)); return repoResults; } diff --git a/DnsServerCore/WebServiceAppsApi.cs b/DnsServerCore/WebServiceAppsApi.cs index 20baeef3..c885cae9 100644 --- a/DnsServerCore/WebServiceAppsApi.cs +++ b/DnsServerCore/WebServiceAppsApi.cs @@ -283,18 +283,21 @@ public async Task ListCustomRepositoryAppsAsync(HttpContext context) if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, sessionUser, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - IReadOnlyList<(string repoUrl, string jsonData, string error)> repoResults = await _dnsWebService._dnsServer.DnsApplicationManager.GetCustomRepositoriesStoreAppsJsonDataAsync(); + IReadOnlyList<(string name, string repoUrl, string jsonData, string error)> repoResults = await _dnsWebService._dnsServer.DnsApplicationManager.GetCustomRepositoriesStoreAppsJsonDataAsync(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); //parse each repo's data upfront so a parse failure can be reported as the repo's error too, not just a fetch failure Dictionary parsedRepoData = new Dictionary(); + Dictionary repoNames = new Dictionary(); Dictionary repoErrors = new Dictionary(); try { - foreach ((string repoUrl, string jsonData, string fetchError) in repoResults) + foreach ((string name, string repoUrl, string jsonData, string fetchError) in repoResults) { + repoNames[repoUrl] = name; + if (fetchError is not null) { repoErrors[repoUrl] = fetchError; @@ -318,10 +321,11 @@ public async Task ListCustomRepositoryAppsAsync(HttpContext context) jsonWriter.WritePropertyName("repositories"); jsonWriter.WriteStartArray(); - foreach ((string repoUrl, _, _) in repoResults) + foreach ((string name, string repoUrl, _, _) in repoResults) { jsonWriter.WriteStartObject(); + jsonWriter.WriteString("name", name); jsonWriter.WriteString("url", repoUrl); if (repoErrors.TryGetValue(repoUrl, out string error)) @@ -338,6 +342,7 @@ public async Task ListCustomRepositoryAppsAsync(HttpContext context) foreach (KeyValuePair parsedRepo in parsedRepoData) { string repoUrl = parsedRepo.Key; + string repoName = repoNames[repoUrl]; foreach (JsonElement jsonStoreApp in parsedRepo.Value.RootElement.EnumerateArray()) { @@ -379,6 +384,7 @@ public async Task ListCustomRepositoryAppsAsync(HttpContext context) jsonWriter.WriteString("url", url); jsonWriter.WriteString("size", size); jsonWriter.WriteString("repository", repoUrl); + jsonWriter.WriteString("repositoryName", repoName); bool installed = _dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication installedApp); @@ -412,9 +418,10 @@ public void AddAppRepository(HttpContext context) HttpRequest request = context.Request; + string name = request.GetQueryOrForm("name", "").Trim(); string url = request.GetQueryOrForm("url").Trim(); - _dnsWebService._dnsServer.DnsApplicationManager.AddCustomRepository(url); + _dnsWebService._dnsServer.DnsApplicationManager.AddCustomRepository(name, url); _dnsWebService._log.Write(_dnsWebService.GetRemoteEndPoint(context), "[" + sessionUser.Username + "] DNS App repository was added: " + url); } diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index 246c5b7a..fb314b77 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -807,7 +807,7 @@

@@ -839,37 +839,38 @@

-
-
+
+

Add a third-party DNS App repository URL (a JSON manifest in the same format as the official DNS App Store) to browse and install apps from it. These apps are not maintained or vetted by Technitium.

- - + + +
- - +
+
- + -
- +
+
- + - + - +
Third Party AppsCommunity Apps
Total Apps: 0
diff --git a/DnsServerCore/www/js/apps.js b/DnsServerCore/www/js/apps.js index 315504b2..f04c951f 100644 --- a/DnsServerCore/www/js/apps.js +++ b/DnsServerCore/www/js/apps.js @@ -528,13 +528,13 @@ function saveAppConfig() { //content - always render them via htmlEncode(), never as raw inline JS string //literals in onclick attributes. -function refreshThirdPartyApps() { - var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); - var divThirdPartyAppsLoader = $("#divThirdPartyAppsLoader"); - var divThirdPartyApps = $("#divThirdPartyApps"); +function refreshCommunityApps() { + var divCommunityAppsAlert = $("#divCommunityAppsAlert"); + var divCommunityAppsLoader = $("#divCommunityAppsLoader"); + var divCommunityApps = $("#divCommunityApps"); - divThirdPartyApps.hide(); - divThirdPartyAppsLoader.show(); + divCommunityApps.hide(); + divCommunityAppsLoader.show(); HTTPRequest({ url: "api/apps/repositories/list", @@ -546,81 +546,90 @@ function refreshThirdPartyApps() { var repoHtmlRows = ""; for (var i = 0; i < repositories.length; i++) - repoHtmlRows += getThirdPartyRepoRowHtml(repositories[i]); + repoHtmlRows += getCommunityRepoRowHtml(repositories[i]); if (repositories.length > 0) - $("#tableThirdPartyReposBody").html(repoHtmlRows); + $("#tableCommunityReposBody").html(repoHtmlRows); else - $("#tableThirdPartyReposBody").html("No Repositories Added"); + $("#tableCommunityReposBody").html("No Repositories Added"); var tableHtmlRows = ""; for (var i = 0; i < storeApps.length; i++) - tableHtmlRows += getThirdPartyStoreAppRowHtml(storeApps[i]); + tableHtmlRows += getCommunityStoreAppRowHtml(storeApps[i]); - $("#tableThirdPartyStoreAppsBody").html(tableHtmlRows); + $("#tableCommunityStoreAppsBody").html(tableHtmlRows); if (storeApps.length > 0) - $("#tableThirdPartyStoreAppsFooter").html("Total Apps: " + storeApps.length + ""); + $("#tableCommunityStoreAppsFooter").html("Total Apps: " + storeApps.length + ""); else - $("#tableThirdPartyStoreAppsFooter").html("No Apps Found"); + $("#tableCommunityStoreAppsFooter").html("No Apps Found"); - divThirdPartyAppsLoader.hide(); - divThirdPartyApps.show(); + divCommunityAppsLoader.hide(); + divCommunityApps.show(); }, error: function () { - divThirdPartyAppsLoader.hide(); - divThirdPartyApps.show(); + divCommunityAppsLoader.hide(); + divCommunityApps.show(); }, invalidToken: function () { showPageLogin(); }, - objAlertPlaceholder: divThirdPartyAppsAlert, - objLoaderPlaceholder: divThirdPartyAppsLoader + objAlertPlaceholder: divCommunityAppsAlert, + objLoaderPlaceholder: divCommunityAppsLoader }); } -function getThirdPartyRepoRowId(url) { +function getCommunityRepoRowId(url) { return btoa(url).replace(/[^a-zA-Z0-9]/g, ""); } -function getThirdPartyRepoRowHtml(repo) { - var id = getThirdPartyRepoRowId(repo.url); +function getCommunityRepoRowHtml(repo) { + var id = getCommunityRepoRowId(repo.url); - var row = "
" + htmlEncode(repo.url) + "
"; + var row = "
" + htmlEncode(repo.name) + "
" + htmlEncode(repo.url) + "
"; if (repo.error != null) row += "
Unreachable: " + htmlEncode(repo.error) + "
"; - row += ""; + row += ""; return row; } -function addThirdPartyRepository() { - var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); - var txtThirdPartyRepoUrl = $("#txtThirdPartyRepoUrl"); - var url = txtThirdPartyRepoUrl.val(); +function addCommunityRepository() { + var divCommunityAppsAlert = $("#divCommunityAppsAlert"); + var txtCommunityRepoName = $("#txtCommunityRepoName"); + var txtCommunityRepoUrl = $("#txtCommunityRepoUrl"); + var name = txtCommunityRepoName.val(); + var url = txtCommunityRepoUrl.val(); + + if ((name === null) || (name === "")) { + showAlert("warning", "Missing!", "Please enter a name for the DNS App repository.", divCommunityAppsAlert); + txtCommunityRepoName.trigger("focus"); + return; + } if ((url === null) || (url === "")) { - showAlert("warning", "Missing!", "Please enter a DNS App repository URL.", divThirdPartyAppsAlert); - txtThirdPartyRepoUrl.trigger("focus"); + showAlert("warning", "Missing!", "Please enter a DNS App repository URL.", divCommunityAppsAlert); + txtCommunityRepoUrl.trigger("focus"); return; } - var btn = $("#btnThirdPartyRepoAdd"); + var btn = $("#btnCommunityRepoAdd"); btn.button("loading"); HTTPRequest({ - url: "api/apps/repositories/add?url=" + encodeURIComponent(url), + url: "api/apps/repositories/add?name=" + encodeURIComponent(name) + "&url=" + encodeURIComponent(url), token: sessionData.token, success: function (responseJSON) { btn.button("reset"); - txtThirdPartyRepoUrl.val(""); + txtCommunityRepoName.val(""); + txtCommunityRepoUrl.val(""); - showAlert("success", "Repository Added!", "DNS App repository was added successfully.", divThirdPartyAppsAlert); + showAlert("success", "Repository Added!", "DNS App repository was added successfully.", divCommunityAppsAlert); - refreshThirdPartyApps(); + refreshCommunityApps(); }, error: function () { btn.button("reset"); @@ -628,18 +637,18 @@ function addThirdPartyRepository() { invalidToken: function () { showPageLogin(); }, - objAlertPlaceholder: divThirdPartyAppsAlert + objAlertPlaceholder: divCommunityAppsAlert }); } -function removeThirdPartyRepository(objBtn) { +function removeCommunityRepository(objBtn) { var btn = $(objBtn); var url = btn.attr("data-url"); if (!confirm("Are you sure you want to remove the DNS App repository '" + url + "'?")) return; - var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); + var divCommunityAppsAlert = $("#divCommunityAppsAlert"); btn.button("loading"); @@ -647,9 +656,9 @@ function removeThirdPartyRepository(objBtn) { url: "api/apps/repositories/remove?url=" + encodeURIComponent(url), token: sessionData.token, success: function (responseJSON) { - showAlert("success", "Repository Removed!", "DNS App repository was removed successfully.", divThirdPartyAppsAlert); + showAlert("success", "Repository Removed!", "DNS App repository was removed successfully.", divCommunityAppsAlert); - refreshThirdPartyApps(); + refreshCommunityApps(); }, error: function () { btn.button("reset"); @@ -657,40 +666,40 @@ function removeThirdPartyRepository(objBtn) { invalidToken: function () { showPageLogin(); }, - objAlertPlaceholder: divThirdPartyAppsAlert + objAlertPlaceholder: divCommunityAppsAlert }); } -function getThirdPartyStoreAppRowHtml(app) { +function getCommunityStoreAppRowHtml(app) { var id = Math.floor(Math.random() * 1000000); var name = app.name; var version = app.version; var description = app.description; var url = app.url; var size = app.size; - var repository = app.repository; + var repositoryName = app.repositoryName; var installed = app.installed; var installedVersion = app.installedVersion; var updateAvailable = installed ? app.updateAvailable : false; var displayVersion = installed ? installedVersion : version; - var row = "
" + htmlEncode(name) + "
"; - row += "Version " + htmlEncode(displayVersion) + " "; - row += "Update " + htmlEncode(version) + "
"; + var row = "
" + htmlEncode(name) + "
"; + row += "Version " + htmlEncode(displayVersion) + " "; + row += "Update " + htmlEncode(version) + "
"; row += "
" + htmlEncode(description).replace(/\n/g, "
") + "
"; - row += "
Repository: " + htmlEncode(repository) + "
App Zip File: " + htmlEncode(url) + "
Size: " + htmlEncode(size) + "
"; + row += "
Repository: " + htmlEncode(repositoryName) + "
App Zip File: " + htmlEncode(url) + "
Size: " + htmlEncode(size) + "
"; - row += ""; - row += ""; - row += ""; + row += ""; + row += ""; + row += ""; row += ""; return row; } -function installThirdPartyStoreApp(objBtn) { - var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); +function installCommunityStoreApp(objBtn) { + var divCommunityAppsAlert = $("#divCommunityAppsAlert"); var btn = $(objBtn); var appName = btn.attr("data-name"); var url = btn.attr("data-url"); @@ -705,13 +714,13 @@ function installThirdPartyStoreApp(objBtn) { btn.hide(); var id = btn.attr("data-id"); - $("#btnThirdPartyStoreAppUninstall" + id).show(); + $("#btnCommunityStoreAppUninstall" + id).show(); var tableHtmlRow = getAppRowHtml(responseJSON.response.installedApp); $("#tableAppsBody").prepend(tableHtmlRow); updateAppsFooterCount(); - showAlert("success", "App Installed!", "DNS application '" + appName + "' was installed successfully from the third-party repository.", divThirdPartyAppsAlert); + showAlert("success", "App Installed!", "DNS application '" + appName + "' was installed successfully from the third-party repository.", divCommunityAppsAlert); }, error: function () { btn.button("reset"); @@ -719,12 +728,12 @@ function installThirdPartyStoreApp(objBtn) { invalidToken: function () { showPageLogin(); }, - objAlertPlaceholder: divThirdPartyAppsAlert + objAlertPlaceholder: divCommunityAppsAlert }); } -function updateThirdPartyStoreApp(objBtn) { - var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); +function updateCommunityStoreApp(objBtn) { + var divCommunityAppsAlert = $("#divCommunityAppsAlert"); var btn = $(objBtn); var appName = btn.attr("data-name"); var url = btn.attr("data-url"); @@ -739,14 +748,14 @@ function updateThirdPartyStoreApp(objBtn) { btn.hide(); var id = btn.attr("data-id"); - $("#spanThirdPartyStoreAppUpdateVersion" + id).hide(); - $("#spanThirdPartyStoreAppDisplayVersion" + id).text($("#spanThirdPartyStoreAppUpdateVersion" + id).text().replace(/Update/g, "Version")); + $("#spanCommunityStoreAppUpdateVersion" + id).hide(); + $("#spanCommunityStoreAppDisplayVersion" + id).text($("#spanCommunityStoreAppUpdateVersion" + id).text().replace(/Update/g, "Version")); var tableHtmlRow = getAppRowHtml(responseJSON.response.updatedApp); var appRowId = getAppRowId(responseJSON.response.updatedApp.name); $("#trApp" + appRowId).replaceWith(tableHtmlRow); - showAlert("success", "App Updated!", "DNS application '" + appName + "' was updated successfully from the third-party repository.", divThirdPartyAppsAlert); + showAlert("success", "App Updated!", "DNS application '" + appName + "' was updated successfully from the third-party repository.", divCommunityAppsAlert); }, error: function () { btn.button("reset"); @@ -754,18 +763,18 @@ function updateThirdPartyStoreApp(objBtn) { invalidToken: function () { showPageLogin(); }, - objAlertPlaceholder: divThirdPartyAppsAlert + objAlertPlaceholder: divCommunityAppsAlert }); } -function uninstallThirdPartyStoreApp(objBtn) { +function uninstallCommunityStoreApp(objBtn) { var btn = $(objBtn); var appName = btn.attr("data-name"); if (!confirm("Are you sure you want to uninstall the DNS application '" + appName + "'?")) return; - var divThirdPartyAppsAlert = $("#divThirdPartyAppsAlert"); + var divCommunityAppsAlert = $("#divCommunityAppsAlert"); btn.button("loading"); @@ -777,14 +786,14 @@ function uninstallThirdPartyStoreApp(objBtn) { btn.hide(); var id = btn.attr("data-id"); - $("#btnThirdPartyStoreAppInstall" + id).show(); - $("#btnThirdPartyStoreAppUpdate" + id).hide(); + $("#btnCommunityStoreAppInstall" + id).show(); + $("#btnCommunityStoreAppUpdate" + id).hide(); var appRowId = getAppRowId(appName); $("#trApp" + appRowId).remove(); updateAppsFooterCount(); - showAlert("success", "App Uninstalled!", "DNS application '" + appName + "' was uninstalled successfully.", divThirdPartyAppsAlert); + showAlert("success", "App Uninstalled!", "DNS application '" + appName + "' was uninstalled successfully.", divCommunityAppsAlert); }, error: function () { btn.button("reset"); @@ -792,6 +801,6 @@ function uninstallThirdPartyStoreApp(objBtn) { invalidToken: function () { showPageLogin(); }, - objAlertPlaceholder: divThirdPartyAppsAlert + objAlertPlaceholder: divCommunityAppsAlert }); } From 40e669abb11c4f195e0e2ab22d686be1aad6fe3d Mon Sep 17 00:00:00 2001 From: Roy Hagland Date: Wed, 22 Jul 2026 12:01:56 +0200 Subject: [PATCH 4/9] Fix crash when a repository's root JSON is an object, and accept it A repository whose manifest is a single bare app object (as some single-app repositories publish, e.g. the schema used in TechnitiumSoftware/DnsServer#2058) previously crashed the entire repositories/list call at EnumerateArray() on the object root, taking down every other configured repository's listing along with it. The per-repo try/catch around JsonDocument.Parse never caught this, since Parse succeeds on a valid object and the failure happened later in a separate, unguarded loop. Now the root shape is checked right after parsing (array or object both accepted; anything else is a per-repo error, same as invalid JSON) and each individual app entry is processed in its own try/catch so one malformed entry can't take down its siblings or the repo. --- DnsServerCore/WebServiceAppsApi.cs | 106 ++++++++++++++++++----------- 1 file changed, 66 insertions(+), 40 deletions(-) diff --git a/DnsServerCore/WebServiceAppsApi.cs b/DnsServerCore/WebServiceAppsApi.cs index c885cae9..ffb9aaa6 100644 --- a/DnsServerCore/WebServiceAppsApi.cs +++ b/DnsServerCore/WebServiceAppsApi.cs @@ -307,15 +307,30 @@ public async Task ListCustomRepositoryAppsAsync(HttpContext context) if (jsonData is null) continue; //should not happen when fetchError is null, but guard anyway + JsonDocument jsonDocument; + try { - parsedRepoData[repoUrl] = JsonDocument.Parse(jsonData); + jsonDocument = JsonDocument.Parse(jsonData); } catch (Exception ex) { _dnsWebService._log.Write("DNS App repository returned invalid JSON data: " + repoUrl, ex); repoErrors[repoUrl] = "Repository data is not valid JSON: " + ex.Message; + continue; + } + + //a repository is expected to be a JSON array of app entries, but also accept a single + //app entry as a bare JSON object (as published directly by some single-app repositories) + JsonValueKind rootKind = jsonDocument.RootElement.ValueKind; + if ((rootKind != JsonValueKind.Array) && (rootKind != JsonValueKind.Object)) + { + jsonDocument.Dispose(); + repoErrors[repoUrl] = "Repository data must be a JSON array of app entries or a single app entry object."; + continue; } + + parsedRepoData[repoUrl] = jsonDocument; } jsonWriter.WritePropertyName("repositories"); @@ -343,60 +358,71 @@ public async Task ListCustomRepositoryAppsAsync(HttpContext context) { string repoUrl = parsedRepo.Key; string repoName = repoNames[repoUrl]; + JsonElement root = parsedRepo.Value.RootElement; - foreach (JsonElement jsonStoreApp in parsedRepo.Value.RootElement.EnumerateArray()) - { - string name = jsonStoreApp.GetProperty("name").GetString(); - string description = jsonStoreApp.GetProperty("description").GetString(); - string version = null; - string url = null; - string size = null; - Version storeAppVersion = null; - Version lastServerVersion = null; + IEnumerable jsonStoreApps = (root.ValueKind == JsonValueKind.Array) ? root.EnumerateArray() : new[] { root }; - foreach (JsonElement jsonVersion in jsonStoreApp.GetProperty("versions").EnumerateArray()) + foreach (JsonElement jsonStoreApp in jsonStoreApps) + { + try { - string strServerVersion = jsonVersion.GetProperty("serverVersion").GetString(); - Version requiredServerVersion = new Version(strServerVersion); + string name = jsonStoreApp.GetProperty("name").GetString(); + string description = jsonStoreApp.GetProperty("description").GetString(); + string version = null; + string url = null; + string size = null; + Version storeAppVersion = null; + Version lastServerVersion = null; - if (_dnsWebService._currentVersion < requiredServerVersion) - continue; + foreach (JsonElement jsonVersion in jsonStoreApp.GetProperty("versions").EnumerateArray()) + { + string strServerVersion = jsonVersion.GetProperty("serverVersion").GetString(); + Version requiredServerVersion = new Version(strServerVersion); - if ((lastServerVersion is not null) && (lastServerVersion > requiredServerVersion)) - continue; + if (_dnsWebService._currentVersion < requiredServerVersion) + continue; - version = jsonVersion.GetProperty("version").GetString(); - url = jsonVersion.GetProperty("url").GetString(); - size = jsonVersion.GetProperty("size").GetString(); + if ((lastServerVersion is not null) && (lastServerVersion > requiredServerVersion)) + continue; - storeAppVersion = new Version(version); - lastServerVersion = requiredServerVersion; - } + version = jsonVersion.GetProperty("version").GetString(); + url = jsonVersion.GetProperty("url").GetString(); + size = jsonVersion.GetProperty("size").GetString(); - if (storeAppVersion is null) - continue; //app is not compatible with this server version + storeAppVersion = new Version(version); + lastServerVersion = requiredServerVersion; + } + + if (storeAppVersion is null) + continue; //app is not compatible with this server version - jsonWriter.WriteStartObject(); + jsonWriter.WriteStartObject(); - jsonWriter.WriteString("name", name); - jsonWriter.WriteString("description", description); - jsonWriter.WriteString("version", version); - jsonWriter.WriteString("url", url); - jsonWriter.WriteString("size", size); - jsonWriter.WriteString("repository", repoUrl); - jsonWriter.WriteString("repositoryName", repoName); + jsonWriter.WriteString("name", name); + jsonWriter.WriteString("description", description); + jsonWriter.WriteString("version", version); + jsonWriter.WriteString("url", url); + jsonWriter.WriteString("size", size); + jsonWriter.WriteString("repository", repoUrl); + jsonWriter.WriteString("repositoryName", repoName); - bool installed = _dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication installedApp); + bool installed = _dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication installedApp); - jsonWriter.WriteBoolean("installed", installed); + jsonWriter.WriteBoolean("installed", installed); - if (installed) + if (installed) + { + jsonWriter.WriteString("installedVersion", DnsWebService.GetCleanVersion(installedApp.Version)); + jsonWriter.WriteBoolean("updateAvailable", storeAppVersion > installedApp.Version); + } + + jsonWriter.WriteEndObject(); + } + catch (Exception ex) { - jsonWriter.WriteString("installedVersion", DnsWebService.GetCleanVersion(installedApp.Version)); - jsonWriter.WriteBoolean("updateAvailable", storeAppVersion > installedApp.Version); + //a single malformed app entry must not break the rest of this repo's listing, nor any other repo's + _dnsWebService._log.Write("DNS App repository has a malformed app entry: " + repoUrl, ex); } - - jsonWriter.WriteEndObject(); } } } From a199546d4e4c4abc45a9de7770d2972c9ac21e3e Mon Sep 17 00:00:00 2001 From: Roy Hagland Date: Wed, 22 Jul 2026 12:06:54 +0200 Subject: [PATCH 5/9] Document that community app updates are manual-only Confirmed with user: community/third-party repo apps deliberately do not participate in the existing automatic update timer, which only checks the official DNS App Store. Documented this as an intentional scope decision rather than a silent gap. --- APIDOCS.md | 4 +++- DnsServerCore/www/index.html | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/APIDOCS.md b/APIDOCS.md index 0ef07212..57535f02 100644 --- a/APIDOCS.md +++ b/APIDOCS.md @@ -4691,7 +4691,9 @@ RESPONSE: ### List Community App Repository Apps -Lists apps available from all configured community (third-party) DNS App repositories. A repository is any HTTPS URL serving a JSON manifest in the same schema as the official DNS App Store. Each configured repository is fetched independently; if a repository is unreachable or returns invalid data, it is reported with an `error` and does not affect the other repositories' listings. +Lists apps available from all configured community (third-party) DNS App repositories. A repository is any HTTPS URL serving a JSON manifest in the same schema as the official DNS App Store (a JSON array of app entries, or a single app entry as a bare JSON object). Each configured repository is fetched independently; if a repository is unreachable, returns invalid JSON, or has an unsupported JSON shape, it is reported with an `error` and does not affect the other repositories' listings. + +Unlike the official DNS App Store, apps installed from a community repository are **not** covered by the automatic update timer (`EnableAutomaticUpdate` DNS setting) — that timer only checks the official store. Updates for community apps must be applied manually via `downloadAndUpdate` after calling this endpoint to check for a newer version. URL:\ `http://localhost:5380/api/apps/repositories/list` diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index fb314b77..db7d6cf2 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -844,7 +844,7 @@

-

Add a third-party DNS App repository URL (a JSON manifest in the same format as the official DNS App Store) to browse and install apps from it. These apps are not maintained or vetted by Technitium.

+

Add a third-party DNS App repository URL (a JSON manifest in the same format as the official DNS App Store) to browse and install apps from it. These apps are not maintained or vetted by Technitium. Updates for these apps are not automatic; check back here and click Update when a new version is available.

From 942c313076299b14d5ba3f6b486e90131125c745 Mon Sep 17 00:00:00 2001 From: Roy Hagland Date: Wed, 22 Jul 2026 12:21:59 +0200 Subject: [PATCH 6/9] Reset Apps tab to the Installed sub-tab when navigating to it Clicking the top-level Apps tab left whichever sub-tab (Installed or Community) was last active, unlike other tabbed sections which reset to their first pane. Now it always shows Installed apps first. --- DnsServerCore/www/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index db7d6cf2..869c4a69 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -150,7 +150,7 @@

DNS Server

- + From c259c76fe98c2bc26641c92442745779ac60ef42 Mon Sep 17 00:00:00 2001 From: Roy Hagland Date: Wed, 22 Jul 2026 13:07:37 +0200 Subject: [PATCH 7/9] Add Community badge to installed community-sourced apps and document repository manifests Community-installed apps share the same Installed Apps table as official store apps. Cross-references api/apps/repositories/list (already tracks per-app installed state for the Community tab) against api/apps/list purely client-side to flag matching rows, so official app rendering, apps/list, and the install/update/uninstall endpoints are untouched. Also adds CommunityAppRepositories.md documenting the manifest schema for admins installing community apps and authors publishing them. --- APIDOCS.md | 2 +- CommunityAppRepositories.md | 82 ++++++++++++++++++++++++++++++++++++ DnsServerCore/www/js/apps.js | 68 ++++++++++++++++++++---------- 3 files changed, 129 insertions(+), 23 deletions(-) create mode 100644 CommunityAppRepositories.md diff --git a/APIDOCS.md b/APIDOCS.md index 57535f02..2b1e7e7b 100644 --- a/APIDOCS.md +++ b/APIDOCS.md @@ -4691,7 +4691,7 @@ RESPONSE: ### List Community App Repository Apps -Lists apps available from all configured community (third-party) DNS App repositories. A repository is any HTTPS URL serving a JSON manifest in the same schema as the official DNS App Store (a JSON array of app entries, or a single app entry as a bare JSON object). Each configured repository is fetched independently; if a repository is unreachable, returns invalid JSON, or has an unsupported JSON shape, it is reported with an `error` and does not affect the other repositories' listings. +Lists apps available from all configured community (third-party) DNS App repositories. A repository is any HTTPS URL serving a JSON manifest in the same schema as the official DNS App Store (a JSON array of app entries, or a single app entry as a bare JSON object). Each configured repository is fetched independently; if a repository is unreachable, returns invalid JSON, or has an unsupported JSON shape, it is reported with an `error` and does not affect the other repositories' listings. See `CommunityAppRepositories.md` for the full manifest schema and a guide for app authors who want to publish one. Unlike the official DNS App Store, apps installed from a community repository are **not** covered by the automatic update timer (`EnableAutomaticUpdate` DNS setting) — that timer only checks the official store. Updates for community apps must be applied manually via `downloadAndUpdate` after calling this endpoint to check for a newer version. diff --git a/CommunityAppRepositories.md b/CommunityAppRepositories.md new file mode 100644 index 00000000..6f6885ad --- /dev/null +++ b/CommunityAppRepositories.md @@ -0,0 +1,82 @@ +# Community DNS App Repositories + +DNS Server admins can add any HTTPS URL as a "Community" DNS App repository from the Apps → Community tab, giving apps that aren't accepted into the official DNS App Store (for example because they need hardware/infrastructure the maintainer can't test against — see [issue #2058](https://github.com/TechnitiumSoftware/DnsServer/issues/2058)) a distribution path of their own. + +This document covers both sides: admins who want to **install** someone else's community app, and authors who want to **publish** one. For the admin-facing API itself (`apps/repositories/add`, `apps/repositories/list`, `apps/repositories/remove`), see `APIDOCS.md`. + +## Installing someone else's community app + +There's no central index or directory of community repositories — this is a decentralized, ad-hoc distribution model, not a curated store like the official DNS App Store. To install an app someone else published: + +1. Get the repository's manifest URL directly from the app author — their project's README, GitHub repo, an issue/PR discussion, or wherever they've shared it (Technitium community forums/Discord/Reddit, etc.). +2. In the DNS Server web console, go to Apps → Community, and add that URL as a repository (give it any display name you like). +3. If the app has a version compatible with your server, it shows up in the Community tab's app list with an Install button. + +Since nothing here is vetted or reviewed, only add repository URLs from authors/sources you trust — an installed app runs as native code inside the DNS server process. See "No checksum or signature verification" below. + +## Publishing your own community app + +The rest of this document is for **app authors** who want their app installable this way. + +### What you need to host + +A repository is just a static JSON file served over HTTPS — a GitHub raw URL, a GitHub Pages page, a gist, anything that returns the right JSON. There's no submission process and no approval; the admin who wants your app pastes your manifest URL into their server. + +The manifest is the exact same schema the official DNS App Store uses: either a JSON array of app entries, or a single app entry as a bare JSON object (useful if your repo only ever serves one app). + +```json +[ + { + "name": "Example Community App", + "description": "One-line description shown in the Community tab's app list.", + "versions": [ + { + "serverVersion": "15.0", + "version": "1.0.0", + "url": "https://github.com/you/your-app/releases/download/v1.0.0/YourApp-1.0.0.zip", + "size": "12.3 KB" + }, + { + "serverVersion": "15.4", + "version": "1.1.0", + "url": "https://github.com/you/your-app/releases/download/v1.1.0/YourApp-1.1.0.zip", + "size": "13.1 KB" + } + ] + }, + { + "name": "Another Community App", + "description": "A second, unrelated app served from the same repository.", + "versions": [ + { + "serverVersion": "15.0", + "version": "2.3.0", + "url": "https://github.com/someone-else/another-app/releases/download/v2.3.0/AnotherApp-2.3.0.zip", + "size": "8.7 KB" + } + ] + } +] +``` + +A single repository can serve as many app entries as you like — one repo isn't limited to one app. Each entry is looked up and resolved independently by `name`, so unrelated apps (even from different authors) can share one manifest URL. + +Field notes: + +- **`name`** must exactly match the app name your app registers with the DNS Server (the name shown in the Installed Apps list). The server uses this string as the install/uninstall/update key — a mismatch means "installed" detection and updates silently won't work. +- **`description`** is plain text (rendered HTML-encoded), shown in the Community tab. +- **`versions`** is a list, not a single object, even if you only ever publish one version. Each entry: + - **`serverVersion`**: the minimum DNS Server version this build requires. + - **`version`**: your app's version string. + - **`url`**: direct HTTPS download link to the `.zip` package (same package format as a manual/sideloaded app install — same as what you'd upload via Apps → Install from Zip). + - **`size`**: a human-readable size string (e.g. `"50.02 KB"`). It's display-only, not validated against the actual download. +- When resolving which version to offer, the server picks the entry with the **highest `serverVersion` that is still `<=` the running server's version**. This lets you publish multiple builds targeting different server compatibility ranges in one manifest, same as the official store does. +- Any entry the server can't parse (missing fields, bad JSON) is skipped without breaking the rest of your manifest or any other configured repository. + +### No checksum or signature verification + +Same trust model as the official store: the server fetches your `url` and installs whatever `.zip` is there over HTTPS. There is no checksum/signature check on the package. An admin adding your repository URL is trusting your HTTPS endpoint (and its release infrastructure) directly — say so in your own README if you use a mutable "latest" URL versus a pinned release tag. + +### Writing the app itself + +This repository's manifest format only covers *distribution*. For the actual app implementation (the interfaces to implement, how config/records/query logging hooks work), the `DnsServerCore.ApplicationCommon` project's interfaces (`IDnsApplication`, `IDnsQueryLogger`, `IDnsAuthoritativeRequestHandler`, `IDnsRequestBlockingHandler`, `IDnsAppRecordRequestHandler`, `IDnsPostProcessor`, etc.) are the contract, and the `Apps/` folder in this repository has working, real examples (e.g. `Apps/DnsBlockListApp`, `Apps/QueryLogsSqliteApp`) to copy patterns from. diff --git a/DnsServerCore/www/js/apps.js b/DnsServerCore/www/js/apps.js index f04c951f..32bb4b70 100644 --- a/DnsServerCore/www/js/apps.js +++ b/DnsServerCore/www/js/apps.js @@ -25,42 +25,66 @@ function refreshApps() { divViewAppsLoader.show(); HTTPRequest({ - url: "api/apps/list", + url: "api/apps/repositories/list", token: sessionData.token, success: function (responseJSON) { - var apps = responseJSON.response.apps; - var tableHtmlRows = ""; + var storeApps = responseJSON.response.storeApps; + var communityAppNames = {}; - for (var i = 0; i < apps.length; i++) { - tableHtmlRows += getAppRowHtml(apps[i]); + for (var i = 0; i < storeApps.length; i++) { + if (storeApps[i].installed) + communityAppNames[storeApps[i].name] = true; } - $("#tableAppsBody").html(tableHtmlRows); - - if (apps.length > 0) - $("#tableAppsFooter").html("Total Apps: " + apps.length + ""); - else - $("#tableAppsFooter").html("No Apps Found"); - - divViewAppsLoader.hide(); - divViewApps.show(); + refreshAppsList(communityAppNames); }, error: function () { - divViewAppsLoader.hide(); - divViewApps.show(); + refreshAppsList({}); }, invalidToken: function () { showPageLogin(); - }, - objLoaderPlaceholder: divViewAppsLoader + } }); + + function refreshAppsList(communityAppNames) { + HTTPRequest({ + url: "api/apps/list", + token: sessionData.token, + success: function (responseJSON) { + var apps = responseJSON.response.apps; + var tableHtmlRows = ""; + + for (var i = 0; i < apps.length; i++) { + tableHtmlRows += getAppRowHtml(apps[i], communityAppNames[apps[i].name] === true); + } + + $("#tableAppsBody").html(tableHtmlRows); + + if (apps.length > 0) + $("#tableAppsFooter").html("Total Apps: " + apps.length + ""); + else + $("#tableAppsFooter").html("No Apps Found"); + + divViewAppsLoader.hide(); + divViewApps.show(); + }, + error: function () { + divViewAppsLoader.hide(); + divViewApps.show(); + }, + invalidToken: function () { + showPageLogin(); + }, + objLoaderPlaceholder: divViewAppsLoader + }); + } } function getAppRowId(appName) { return btoa(appName).replace(/=/g, ""); } -function getAppRowHtml(app) { +function getAppRowHtml(app, isCommunity) { var name = app.name; var version = app.version; var updateVersion = app.updateVersion; @@ -113,7 +137,7 @@ function getAppRowHtml(app) { } var id = getAppRowId(name); - var tableHtmlRow = "
" + htmlEncode(name) + "
Version " + htmlEncode(version) + " Update " + htmlEncode(updateVersion) + "
"; + var tableHtmlRow = "
" + htmlEncode(name) + "
Version " + htmlEncode(version) + " Update " + htmlEncode(updateVersion) + " " + (isCommunity ? "Community" : "") + "
"; if (app.description != null) tableHtmlRow += "
" + htmlEncode(app.description).replace(/\n/g, "
") + "
"; @@ -716,7 +740,7 @@ function installCommunityStoreApp(objBtn) { var id = btn.attr("data-id"); $("#btnCommunityStoreAppUninstall" + id).show(); - var tableHtmlRow = getAppRowHtml(responseJSON.response.installedApp); + var tableHtmlRow = getAppRowHtml(responseJSON.response.installedApp, true); $("#tableAppsBody").prepend(tableHtmlRow); updateAppsFooterCount(); @@ -751,7 +775,7 @@ function updateCommunityStoreApp(objBtn) { $("#spanCommunityStoreAppUpdateVersion" + id).hide(); $("#spanCommunityStoreAppDisplayVersion" + id).text($("#spanCommunityStoreAppUpdateVersion" + id).text().replace(/Update/g, "Version")); - var tableHtmlRow = getAppRowHtml(responseJSON.response.updatedApp); + var tableHtmlRow = getAppRowHtml(responseJSON.response.updatedApp, true); var appRowId = getAppRowId(responseJSON.response.updatedApp.name); $("#trApp" + appRowId).replaceWith(tableHtmlRow); From deb8c582092e06ff4c613f1e3106282b51fd0769 Mon Sep 17 00:00:00 2001 From: Roy Hagland Date: Wed, 22 Jul 2026 13:25:18 +0200 Subject: [PATCH 8/9] Add independent automatic update setting for Community DNS Apps Community-installed apps previously required manual updates. Adds a separate dnsAppsEnableAutomaticUpdateCommunity setting and daily timer, independent of the official DNS App Store's dnsAppsEnableAutomaticUpdate, so disabling one has no effect on the other. Persisted in the existing appRepositories.config file (bumped to v3) rather than the core dns.config. Also relabels the three Software Update checkboxes in Settings to be explicit about which update path each one controls (Core DNS Server, Official Apps, Community Apps), and updates APIDOCS.md and CommunityAppRepositories.md accordingly. --- APIDOCS.md | 4 +- CommunityAppRepositories.md | 2 + .../Dns/Applications/DnsApplicationManager.cs | 137 +++++++++++++++++- DnsServerCore/WebServiceSettingsApi.cs | 8 + DnsServerCore/www/index.html | 17 ++- DnsServerCore/www/js/main.js | 4 +- 6 files changed, 163 insertions(+), 9 deletions(-) diff --git a/APIDOCS.md b/APIDOCS.md index 2b1e7e7b..1a3a00d8 100644 --- a/APIDOCS.md +++ b/APIDOCS.md @@ -4693,7 +4693,7 @@ RESPONSE: Lists apps available from all configured community (third-party) DNS App repositories. A repository is any HTTPS URL serving a JSON manifest in the same schema as the official DNS App Store (a JSON array of app entries, or a single app entry as a bare JSON object). Each configured repository is fetched independently; if a repository is unreachable, returns invalid JSON, or has an unsupported JSON shape, it is reported with an `error` and does not affect the other repositories' listings. See `CommunityAppRepositories.md` for the full manifest schema and a guide for app authors who want to publish one. -Unlike the official DNS App Store, apps installed from a community repository are **not** covered by the automatic update timer (`EnableAutomaticUpdate` DNS setting) — that timer only checks the official store. Updates for community apps must be applied manually via `downloadAndUpdate` after calling this endpoint to check for a newer version. +Apps installed from a community repository are covered by their own separate automatic update timer, controlled by the `dnsAppsEnableAutomaticUpdateCommunity` DNS setting (disabled by default) — the official DNS App Store's `dnsAppsEnableAutomaticUpdate` timer only checks the official store and has no effect on community apps. Updates for community apps can also be applied manually via `downloadAndUpdate` after calling this endpoint to check for a newer version. URL:\ `http://localhost:5380/api/apps/repositories/list` @@ -5222,6 +5222,7 @@ RESPONSE: "notifyAllowedNetworks": [], "dnsServerEnableCheckForUpdate": true, "dnsAppsEnableAutomaticUpdate": true, + "dnsAppsEnableAutomaticUpdateCommunity": false, "ipv6Mode": "Disabled", "preferIPv6": false, "enableUdpSocketPool": true, @@ -5431,6 +5432,7 @@ WHERE: - `notifyAllowedNetworks` (optional, cluster parameter): A comma separated list of IP addresses or network addresses that are allowed to Notify all secondary zones. - `dnsServerEnableCheckForUpdate` (optional): Set to `true` to enable the DNS Server to check if an update is available when the Check For Update API is called which usually occurs after a user logs into the Web Console. - `dnsAppsEnableAutomaticUpdate` (optional, cluster parameter): Set to `true` to allow DNS server to automatically update the DNS Apps from the DNS App Store. The DNS Server will check for updates every 24 hrs when this option is enabled. +- `dnsAppsEnableAutomaticUpdateCommunity` (optional, cluster parameter): Set to `true` to allow the DNS server to automatically update apps installed from Community (third-party) DNS App repositories. Independent of `dnsAppsEnableAutomaticUpdate`, which only covers the official DNS App Store. The DNS Server will check for updates every 24 hrs when this option is enabled. Initial value is `false`. - `ipv6Mode` (optional): Valid options are `Disabled`, `Enabled`, and `Preferred`. Initial value is `Disabled`. - `enableUdpSocketPool` (optional): Set this to `true` to enable UDP socket pool. The DNS Server will use UDP socket pool for all outbound DNS-over-UDP requests when enabled. - `socketPoolExcludedPorts` (optional): A comma separated list of port numbers that must be excluded from being used by the UDP socket pool. diff --git a/CommunityAppRepositories.md b/CommunityAppRepositories.md index 6f6885ad..428fd0bf 100644 --- a/CommunityAppRepositories.md +++ b/CommunityAppRepositories.md @@ -14,6 +14,8 @@ There's no central index or directory of community repositories — this is a de Since nothing here is vetted or reviewed, only add repository URLs from authors/sources you trust — an installed app runs as native code inside the DNS server process. See "No checksum or signature verification" below. +By default, community apps are **not** auto-updated, unlike apps from the official DNS App Store. To have the server check daily and automatically download/install newer versions for community apps too, enable "Enable Automatic Update For Community Apps" in Settings → General → Software Update — this is a separate switch from the official store's "Enable Automatic Update", so turning one off does not affect the other. + ## Publishing your own community app The rest of this document is for **app authors** who want their app installable this way. diff --git a/DnsServerCore/Dns/Applications/DnsApplicationManager.cs b/DnsServerCore/Dns/Applications/DnsApplicationManager.cs index 2c85bb8b..eed60d0c 100644 --- a/DnsServerCore/Dns/Applications/DnsApplicationManager.cs +++ b/DnsServerCore/Dns/Applications/DnsApplicationManager.cs @@ -60,6 +60,8 @@ public sealed class DnsApplicationManager : IDisposable const int APP_UPDATE_TIMER_INITIAL_INTERVAL = 10000; const int APP_UPDATE_TIMER_PERIODIC_INTERVAL = 86400000; + Timer _communityAppUpdateTimer; + readonly string _customRepositoriesConfigFile; readonly object _customRepositoriesLock = new object(); List _customRepositories = new List(); @@ -119,6 +121,7 @@ private void Dispose(bool disposing) if (disposing) { _appUpdateTimer?.Dispose(); + _communityAppUpdateTimer?.Dispose(); if (_applications != null) UnloadAllApplications(); @@ -319,6 +322,112 @@ private void StopAutomaticUpdate() } } + private void StartCommunityAutomaticUpdate() + { + if (_communityAppUpdateTimer is null) + { + _communityAppUpdateTimer = new Timer(async delegate (object state) + { + try + { + if (_applications.IsEmpty) + return; + + IReadOnlyList repositories = GetCustomRepositories(); + if (repositories.Count == 0) + return; + + _dnsServer.LogManager.Write("DNS Server has started automatic update check for Community DNS Apps."); + + IReadOnlyList<(string name, string repoUrl, string jsonData, string error)> repoResults = await GetCustomRepositoriesStoreAppsJsonDataAsync(); + + Version currentVersion = Assembly.GetExecutingAssembly().GetName().Version; + + foreach (DnsApplication application in _applications.Values) + { + string bestUrl = null; + Version bestVersion = null; + Version lastServerVersion = null; + + foreach ((_, string repoUrl, string jsonData, _) in repoResults) + { + if (jsonData is null) + continue; + + try + { + using JsonDocument jsonDocument = JsonDocument.Parse(jsonData); + JsonElement root = jsonDocument.RootElement; + + IEnumerable jsonStoreApps = (root.ValueKind == JsonValueKind.Array) ? root.EnumerateArray() : [root]; + + foreach (JsonElement jsonStoreApp in jsonStoreApps) + { + string name = jsonStoreApp.GetProperty("name").GetString(); + if (!name.Equals(application.Name, StringComparison.Ordinal)) + continue; + + foreach (JsonElement jsonVersion in jsonStoreApp.GetProperty("versions").EnumerateArray()) + { + string strServerVersion = jsonVersion.GetProperty("serverVersion").GetString(); + Version requiredServerVersion = new Version(strServerVersion); + + if (currentVersion < requiredServerVersion) + continue; + + if ((lastServerVersion is not null) && (lastServerVersion > requiredServerVersion)) + continue; + + string version = jsonVersion.GetProperty("version").GetString(); + + bestVersion = new Version(version); + bestUrl = jsonVersion.GetProperty("url").GetString(); + lastServerVersion = requiredServerVersion; + } + + break; + } + } + catch (Exception ex) + { + _dnsServer.LogManager.Write("DNS App repository has a malformed manifest and was skipped during Community app automatic update check: " + repoUrl, ex); + } + } + + if ((bestVersion is not null) && (bestVersion > application.Version)) + { + try + { + await DownloadAndUpdateAppAsync(application.Name, new Uri(bestUrl)); + + _dnsServer.LogManager.Write("Community DNS application '" + application.Name + "' was automatically updated successfully from: " + bestUrl); + } + catch (Exception ex) + { + _dnsServer.LogManager.Write("Failed to automatically download and update Community DNS application '" + application.Name + "'.", ex); + } + } + } + } + catch (Exception ex) + { + _dnsServer.LogManager.Write(ex); + } + }); + + _communityAppUpdateTimer.Change(APP_UPDATE_TIMER_INITIAL_INTERVAL, APP_UPDATE_TIMER_PERIODIC_INTERVAL); + } + } + + private void StopCommunityAutomaticUpdate() + { + if (_communityAppUpdateTimer is not null) + { + _communityAppUpdateTimer.Dispose(); + _communityAppUpdateTimer = null; + } + } + internal async Task GetStoreAppsJsonData() { if ((_storeAppsJsonData is null) || (DateTime.UtcNow > _storeAppsJsonDataUpdatedOn.AddSeconds(STORE_APPS_JSON_DATA_CACHE_TIME_SECONDS))) @@ -351,7 +460,7 @@ private void LoadCustomRepositoriesConfig() BinaryReader bR = new BinaryReader(fS); int version = bR.ReadByte(); - if (version > 2) + if (version > 3) throw new InvalidDataException("DNS Apps repositories config version not supported."); int count = bR.ReadInt32(); @@ -374,10 +483,15 @@ private void LoadCustomRepositoriesConfig() } } + bool enableCommunityAutomaticUpdate = (version >= 3) && bR.ReadBoolean(); + lock (_customRepositoriesLock) { _customRepositories = repositories; } + + if (enableCommunityAutomaticUpdate) + StartCommunityAutomaticUpdate(); } } @@ -391,7 +505,7 @@ private void SaveCustomRepositoriesConfig() fS.Write(Encoding.ASCII.GetBytes("AR")); BinaryWriter bW = new BinaryWriter(fS); - bW.Write((byte)2); //version + bW.Write((byte)3); //version bW.Write(_customRepositories.Count); foreach (AppRepository repository in _customRepositories) @@ -399,6 +513,8 @@ private void SaveCustomRepositoriesConfig() fS.WriteShortString(repository.Name); fS.WriteShortString(repository.Url); } + + bW.Write(_communityAppUpdateTimer is not null); } File.Copy(tmpFile, _customRepositoriesConfigFile, true); @@ -813,6 +929,23 @@ public bool EnableAutomaticUpdate } } + public bool EnableCommunityAutomaticUpdate + { + get { return _communityAppUpdateTimer is not null; } + set + { + lock (_customRepositoriesLock) + { + if (value) + StartCommunityAutomaticUpdate(); + else + StopCommunityAutomaticUpdate(); + + SaveCustomRepositoriesConfig(); + } + } + } + #endregion } } diff --git a/DnsServerCore/WebServiceSettingsApi.cs b/DnsServerCore/WebServiceSettingsApi.cs index b6e742ca..d778bad6 100644 --- a/DnsServerCore/WebServiceSettingsApi.cs +++ b/DnsServerCore/WebServiceSettingsApi.cs @@ -98,6 +98,7 @@ private void WriteDnsSettings(Utf8JsonWriter jsonWriter) jsonWriter.WriteBoolean("dnsServerEnableCheckForUpdate", _dnsWebService._dnsServer.EnableCheckForUpdate); jsonWriter.WriteBoolean("dnsAppsEnableAutomaticUpdate", _dnsWebService._dnsServer.DnsApplicationManager.EnableAutomaticUpdate); + jsonWriter.WriteBoolean("dnsAppsEnableAutomaticUpdateCommunity", _dnsWebService._dnsServer.DnsApplicationManager.EnableCommunityAutomaticUpdate); jsonWriter.WriteString("ipv6Mode", _dnsWebService._dnsServer.IPv6Mode.ToString()); jsonWriter.WriteBoolean("preferIPv6", _dnsWebService._dnsServer.IPv6Mode == IPv6Mode.Preferred); @@ -639,6 +640,13 @@ public async Task SetDnsSettingsAsync(HttpContext context) clusterParameters.Add("dnsAppsEnableAutomaticUpdate", dnsAppsEnableAutomaticUpdate.ToString()); } + if (request.TryGetQueryOrForm("dnsAppsEnableAutomaticUpdateCommunity", bool.Parse, out bool dnsAppsEnableAutomaticUpdateCommunity)) + { + _dnsWebService._dnsServer.DnsApplicationManager.EnableCommunityAutomaticUpdate = dnsAppsEnableAutomaticUpdateCommunity; + + clusterParameters.Add("dnsAppsEnableAutomaticUpdateCommunity", dnsAppsEnableAutomaticUpdateCommunity.ToString()); + } + if (request.TryGetQueryOrFormEnum("ipv6Mode", out IPv6Mode ipv6Mode)) _dnsWebService._dnsServer.IPv6Mode = ipv6Mode; else if (request.TryGetQueryOrForm("preferIPv6", bool.Parse, out bool preferIPv6)) diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index 869c4a69..28f71c35 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -844,7 +844,7 @@

-

Add a third-party DNS App repository URL (a JSON manifest in the same format as the official DNS App Store) to browse and install apps from it. These apps are not maintained or vetted by Technitium. Updates for these apps are not automatic; check back here and click Update when a new version is available.

+

Add a third-party DNS App repository URL (a JSON manifest in the same format as the official DNS App Store) to browse and install apps from it. These apps are not maintained or vetted by Technitium. Enable automatic updates for these apps from Settings, or check back here and click Update manually when a new version is available.

@@ -1152,17 +1152,24 @@

-
Enables the DNS Server to check if an update is available when the Check For Update API is called which usually occurs after a user logs into the Web Console.
+
Enables the DNS Server to check if a core DNS Server update is available when the Check For Update API is called which usually occurs after a user logs into the Web Console.
-
The DNS Server will check for DNS Apps update once every day and will automatically download and install the updates.
+
The DNS Server will check for updates to apps installed from the official DNS App Store once every day and will automatically download and install the updates.
+ +
+ +
+
Independently of the option above, the DNS Server will check for updates once every day for apps installed from Community (third-party) DNS App repositories and will automatically download and install the updates.

diff --git a/DnsServerCore/www/js/main.js b/DnsServerCore/www/js/main.js index 91fdc862..c5a44bab 100644 --- a/DnsServerCore/www/js/main.js +++ b/DnsServerCore/www/js/main.js @@ -1196,6 +1196,7 @@ function loadDnsSettings(responseJSON) { $("#chkDnsServerEnableCheckForUpdate").prop("checked", responseJSON.response.dnsServerEnableCheckForUpdate); $("#chkDnsAppsEnableAutomaticUpdate").prop("checked", responseJSON.response.dnsAppsEnableAutomaticUpdate); + $("#chkDnsAppsEnableAutomaticUpdateCommunity").prop("checked", responseJSON.response.dnsAppsEnableAutomaticUpdateCommunity); switch (responseJSON.response.ipv6Mode) { case "Enabled": @@ -1687,8 +1688,9 @@ function saveDnsSettings(objBtn) { var dnsServerEnableCheckForUpdate = $("#chkDnsServerEnableCheckForUpdate").prop("checked"); var dnsAppsEnableAutomaticUpdate = $("#chkDnsAppsEnableAutomaticUpdate").prop("checked"); + var dnsAppsEnableAutomaticUpdateCommunity = $("#chkDnsAppsEnableAutomaticUpdateCommunity").prop("checked"); - formData += "&defaultRecordTtl=" + encodeURIComponent(defaultRecordTtl) + "&defaultNsRecordTtl=" + encodeURIComponent(defaultNsRecordTtl) + "&defaultSoaRecordTtl=" + encodeURIComponent(defaultSoaRecordTtl) + "&defaultResponsiblePerson=" + encodeURIComponent(defaultResponsiblePerson) + "&useSoaSerialDateScheme=" + useSoaSerialDateScheme + "&minSoaRefresh=" + encodeURIComponent(minSoaRefresh) + "&minSoaRetry=" + encodeURIComponent(minSoaRetry) + "&zoneTransferAllowedNetworks=" + encodeURIComponent(zoneTransferAllowedNetworks) + "¬ifyAllowedNetworks=" + encodeURIComponent(notifyAllowedNetworks) + "&dnsServerEnableCheckForUpdate=" + dnsServerEnableCheckForUpdate + "&dnsAppsEnableAutomaticUpdate=" + dnsAppsEnableAutomaticUpdate; + formData += "&defaultRecordTtl=" + encodeURIComponent(defaultRecordTtl) + "&defaultNsRecordTtl=" + encodeURIComponent(defaultNsRecordTtl) + "&defaultSoaRecordTtl=" + encodeURIComponent(defaultSoaRecordTtl) + "&defaultResponsiblePerson=" + encodeURIComponent(defaultResponsiblePerson) + "&useSoaSerialDateScheme=" + useSoaSerialDateScheme + "&minSoaRefresh=" + encodeURIComponent(minSoaRefresh) + "&minSoaRetry=" + encodeURIComponent(minSoaRetry) + "&zoneTransferAllowedNetworks=" + encodeURIComponent(zoneTransferAllowedNetworks) + "¬ifyAllowedNetworks=" + encodeURIComponent(notifyAllowedNetworks) + "&dnsServerEnableCheckForUpdate=" + dnsServerEnableCheckForUpdate + "&dnsAppsEnableAutomaticUpdate=" + dnsAppsEnableAutomaticUpdate + "&dnsAppsEnableAutomaticUpdateCommunity=" + dnsAppsEnableAutomaticUpdateCommunity; } if (includeNodeParameters) { From 71e2a2eec329b59805518549ff0f8b734ab1a165 Mon Sep 17 00:00:00 2001 From: Roy Hagland Date: Wed, 22 Jul 2026 13:47:06 +0200 Subject: [PATCH 9/9] Add screenshots of the Community Apps feature for the PR Community tab (repository management + browsing), the Community badge in the shared Installed Apps list, and the relabeled Software Update settings. --- docs/screenshots/community-app-badge.png | Bin 0 -> 76764 bytes docs/screenshots/community-apps-tab.png | Bin 0 -> 56694 bytes docs/screenshots/settings-software-update.png | Bin 0 -> 27863 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/screenshots/community-app-badge.png create mode 100644 docs/screenshots/community-apps-tab.png create mode 100644 docs/screenshots/settings-software-update.png diff --git a/docs/screenshots/community-app-badge.png b/docs/screenshots/community-app-badge.png new file mode 100644 index 0000000000000000000000000000000000000000..de2cba790c2f252082976511030e9d4324200746 GIT binary patch literal 76764 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 A<^IcLK;2UH?Jd!M~OW?Q4`u>_HHPv4r)1& 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

DFRVir@MM@>BDS<^1`O+%{c<&D{16z;%Xx#B z=ca?HP%ZpYJIt!?XTdlJZ`-|!#cALL0&J5Vbm=Z7&9c|lxy`_l*+yv&UGGLO53W1l z?u8M%MR0?+wriT?ekQ@hzh$~BIXoR4kDE6l+md#VgTH;Dc1vu3hC!MydvA`MWD^an zpdxZ@W=YFGds?Pf8MDjHM-h7pmud0cMQ(vDXRpTVj{{S5Z_zxaSE)G|axn_XJ{_ZF zdDnOglO{^ND zpGDWE9qCz+zXx{e?1EVheil1`3NqJN{lYj~Q*jWA5;@kPK|>EdUAlQJA<+~t9(g>_ zYT|s+ym~dw^oG?MI42Ov{Mg+=Xq>-&BeY}enn5j){759|bV_uqRGr!Z!65C5uS87x zRZqT8`ZuGk&Ul*^?fa!+#CC?kM;G!hO}w55ET+S};af;Mu7T|S#fYm5zkEdChU35u zYu9t%7z7@G`tgV&(v=xkhh=b4B@hY?E)%dZV z;Ybo5@Z~APB_=^mvI-}dU9%9IotS=qNT%FX%4e`h2BLpiwa^ee?{PqA$u$H;_hT-> zm!?mr{(f)&a0n(5dXBf)TK?Ycem<>dknOvUN*T%iGxEY9ySx4K7l-D7z}FA7Ojjdl|F5#Md8Y^ zN7-@U)4dSK=^Og@*h4$JmW+q>TiC8zUUscVqx2rpa%P|B)^3aZV1wJLa5Uc~4ZQX( zuCz!;V^gyu!Sw>2aEv_UNgx)4mC1 z>3i7a=W|cJ-@Tq7p!!uCc&UptZUkT8+Jp`6?z_Mpn9s&Afj*&!agZUsz?QWR4JfMP zcp=(AhSQ4T8aF=17K>Z2OUKPU=NDC5_I_fA&-+WHngMGK&aQ(*WwQ8#;f3IU zJ@fMkC6~tHqQftdDQ~{exu=}F?ug7?;7awC_y|&oQfdBm6CczL;$xa&8x|3YsBt0V z2wrYR&i**ILdqD-S?~p{ckU;r%Yfz|)Lo1=qLJ?DYB;kh2{oUU^c5=B654G2n=Q`M2*H zS+eZ+wpW+U1q|kfkMNuE=>N!gP`&jh8CldkXs^KhLe>I+H+;LQ(tp6qvWER>wU+K$ zCU>c6^lZOA_&e0${f}D6dG~TEu#-*pzd|YoL0+;MzW)11Go=mY9m~0Wi>Z*S>;9ET zF)=^s?tDD+Z>tl`v?$d2 zdy9FUgSECaszc^Lop}4PGYF*d^67vW^K)%_n(|2iJO69uBfWl~LWRUE@x17UD=hEV(c&L~i>fKGqxa`7UAnPbu2W?$t8qqcUz%QpIJmm^Rkx`; zA}}$UPvwTyVD?3_{nazxWXia5;g@;GyG^dXCtpja$F2Y^vSE)fs$`2l$q*L^U;m-) z2dSx%5Vv<93Z$TdW7TRWDT(3Xo_cXYX@Thyo~=aU)^+90R-aU~mhF`Np6$&RWWDsC znYC*kDdJ_MCksswJS#_!pC+Z&THQc`ssw!86oa&+{G8MGvL%i^jUbTn&CH3y45ivd z?7@=TCliWM2QNEtByeG(z|u@j#O1t z%S`}+o2Jj$yMO2%ifFg}D)qxZwfO~VPULOi2qMpnG&%gp`$!4Cg;?KV6Ab7yeo$FE zweLKn4b|Z`cZm;R(4u=FZ3*k}y8n)cvPC8%&^cW*y_A=vwsU^ZD`wVfH|+ss7^C{M zg8%awvp$qiAbJu{`xXbn{8eVBG3d4=qLT7N-Dt%2DjL_X|Rz;G<`+<`B4>mXZN_x{|)#Pxu!3o+E} z=<0}IavwIA*kkEL*Kcp@xNto0-A3(cUY9OVz+lUbm8_}~3^Ud>yB$OiUggi?+ow^? zRKo?T)yL*omc_0icXoiqkMVe(`o(@hXYhv&Mq$mj&Dv>hA{zm~M_+97iuH$Ja;VOh zrIP%#H2Po_+BaU7$B`D|<@3}f)<@o|&g#yYq`gF)PA@;+?ew842E-6pQ2D<@tqAn} zSSu;jcT9W{|0aPh@t@e6aJDP-n($mUC%7U{(dV@Yn5Ue5 z*k0E04yP>;1Bv|jkv`-b@_|}YN5Dn^f0jab7`a`7-es8H);(`ZD0TPvZ3SIdzIA~Q z)f}abR0GAl3^+lp%#!)*0ib8#Lxfuo;d=BzOnUU^HK9BcPBFv_4sjDODDsJTZEgJR z!fMA(uGFtX8_zlJ06vowlv%n;V@&#!45C!t4;0cfeZc1#MJU144m@`S@e;|2;q|j{ zxL_QDV=QpANS{on>z!{=6(o^q(pl!nJGPjR2lG`F8#Kp`Djo>EDK~Cb<)0xea=gPt z=EpZNeF8hR*K8CMlDY&vBHuHrqZO&5wK5y2X#SCdhB?aPgb(?{4e1 z$Ssko;9(;Lt&0z%N-_@{8g^6SJ_x_00!?IACvPEO-b=lRcD-SbgJVCF?wpK@xsuW_ z&A5q1vW(kdhh5YDF@YvA0L7PPvrKCaDELCDpD@ohp>7cluN{3vkS+dNTmDwF^v+Np zUNYireOAulriVGA(My|a)wHXa`69j!68-l0)K>f3m0VQJ-yK#;BW_o^dn_QltD8g% zs10<3)V{c2fqL0bPgk8qRP^WE!<-<2C2i^=0>152VS3YM2M*tum=6ibbszNfh`)JK z?a2c0hpubR5q-B)t%p)stDnW>-JjOZMcULSeA5liyN-6eD{`&v#(L4YX{t$WT%l?{ zUtEb=#oa)94Hn?r@u__ISe&wDr2UO+4PK$r)JW+738Q|98|dYHw2?-G%waOXvZ1`;VzM_C9g!5kkH z^UXLexXs%*gVU$>MkVz@KU01$3B-s-I%K|Cs(#JbR%h}(euJ7lm;9MN>h_btcjj~W zx7&o>W24+L`EeJA+$i2~A7}OAbDIgvLF(C`{P>kUeMop`F?qXb?|e|P2uI+=Saf4> z)Y)$fzxL+(p2YB7X<@YVk9uL5^H%Fm`x5gV+ClgLs{3}4(c~MWe?{X(I3Q)M-`)(Q z3H!&0C{0P|2(Sr%)C=RsF%9+>8`y1sVmZ|muZHRY86nAA!1ohm1n3Q$lba#kzuu~` z7qv?vhon!49}M2%FJ8K3Do!)uv1O0cfU`zD=`B_}$;RHw{uy=HagV=dE0r8gd}_&M zDK+3jXn>Mp$RiAiBBNTV(?vqv&Ga`bHlh|usK-nN>yTgG*og8e+Qnz3@K4@;`Y7hU z#r)^Z#{yYzwCr?*tXM6I=Sxo@9`{`wOe&`{3j2?Li7OKPc#H~mx*P-r`<*WA1Pq$( z{oGkNEf)+P^*{G7tc4xqumWT8+?8$fJ zIg+;{n1skP7G+N)z8Ki{mxP8kc40IO3g=zA@@}bb{na{efqS(C9XAfr8p-@UQ!+0; zbDh(>KF+J~&HynT!nLr$Mzb{9`SN6b4!c}sitkOm1ool-}ChR@)DzKkXHpa%rAZn z!slRwv|Mf;C*D>&wgt3f_;g((8OTc{@pVMT<`yPLoRy4;D87c}9Rqjlg$o*^t;%sQzaG^?xq@Ay%kXII`7;q=t(S=Rw`MZBJH-?U-iM!WvU)1q z(C4~Fq9PT-`>~?JWTkD;p0y19q3#kp_P_X=ZDV2j_pg%f-r92nQo`{cC_4!to*+@}-YQ^Fg^hxe*9~2!2?Qw8N#+;4ktUz`E0+@~){nwfyyap-EI<2T#VIMC}&jGC#C~r(Xg3B3h3U z8bv-PMO$!dL1N=Kk1p-)w4 z^GHmfW?93Qr*oWhW!(gm5i>V_v@fS}-}t0TG`H>z@eu;g+i#vd7Pd2HhgmJGU0_Nz zsx2k0&}Yf6_B(VaMcZRyyX{A9TBgAO((@eE*XV)qY8g>^^a`?KREi|fX$On5Z4ZN= zLh+9M;P4J7kt{C1%K_u#I@flpxnYSV;Nb!tw4YkC=v@Pv+QypDw6JlC3x z(zSAhxurYh-u(Ioo7in@g{%@1p=*OzrruuCZY>)XLWK$TR?sk9^}D=F>*0HSkgdas zW~Md8RugF6m?YP%6=jjjI5+aJv{qe*LeGob+QRZmQ`)y9gjmz%H@j&x*z*(T`tUMJn*=UMy9rO2eTWrkkaWGjQzQTfnDyv zeD+Q-x)Dp=J#_;z6aItlhqC{|0vZIpqL)XvcT5E2BPzF#6bO2W>y!Alyd&mRUj;pylzAXpHGq1z!>nNaT(q+g zIS?Qtk4={y{j2pRMn-zHVYe`y0jqrUfW+Zm7&rF>G0{*v>C7S5&)e;1ojDEXEAzTU z!4BVM+k})tn{e9e_M#Vk{g=xq3R;GLWR4~*unDc}ct&6T(+9kfv>nC-Wey>uyjVgm z=0z|sy^Nh51$YgEUJH@6%tkADDZM_H~$VK=wMgaRSGkKpqM%lN0=hd-ZU; zWObZ z{>(CPfAVk{1ADj|3kldfyK7Gsd<>#p@Pn>7@I`_pxpo6Jof=-A_lktoYn-=bULmFg z?>q6F06VA;65QFnKm}<~$pS~+e#}Pu=F8c|G6va0kF0+gutW6sZ&&e5l?s1Ew4Ir@ z)U~I>52%2(QOtZk+$R#O^>YvKM9gJ*U=(OwuXvfCuE@tMVE^n`9N4v`|6>){HQd65 z`|WGDTEbJ0FWGz(?-@V@7BxprKxxmV=wt5e-V3@q4T!boXI{DFz^EqbPC>mD_D-JV>vHGY zRIY7&>hvuaIq2mS4h0Hpla=ctoiiU)XZ-djX*vKH@a*cj zTH>FoY0`v*cLy}=E`nh9%}-m3 zRVvt5==J%+4UI*)w$+JigWn(e?svIP-=XG)N07yMYBz7=5i&)awSJsA`YPjR6LR})OS+wkIIMXzqaMg{u1b0yUS1}dpn$PL zwSNZx|5Jc|^<&xpD?!H9`mOFq8(M!4C9A6%k+6&`=3M*p#g&)JRaFQG{w@0X|K;TI zKg?ndr~OQ9r+O8bjO`oROk>ELU|@U>_HxRF?D8hZRRfb+SpV*^liNa1uhZGkK8a*A z^l3Dl2u|$jF6#1qF4bJC>5bE(XPNj@ZF_={aN0&i+o%3j$ZWhrI_%ihHFJIw?fOl$ z(7-#7SjV@hqrC>Eq!6=yyt&VRnx8%B-49cFxqu})^8<){id-5|&%}{aoMp7!HVclz z6IKeL#&bd?O{NdHk~1XnhHk6bNi@6);Ja71Ywe1Zl|Qsjd?d4qD>a#PAZGcwe%=i8 zmw#tpug-DvOiM=O;C+;1;=M2fzBnr7dG!lpyyYvtXdPe2Nqh)QR(nP;%EgK01C`zs zeDho)vk9j6rx|3Vc;*3PI<0|L_;xY4TK*lX^Fx3pMqE0^D{7+Uy5Q&DHt*9H1=@#N z!PqZ%S*`IA2&Q7SIUq~XUnA0@o6bBVtB;y`R8;W--OZ>kOp+UgZ}Iue(5DYHZ);sV z^y}_id|?;(=T4S*GyTVo^kGM`u#5b8`2T9|x}%y*+I?J9Y6J^iiNGoQ^L|SMegb>nh4Bx%S^X>iT zyXV~U-#h1>d1mH3Gf$h}GegkfPh2(J%w*cB#eLdv)=(`{px3`kOs)z5`pYG5=?PNi zPT6jhVBAV?#aq43M^}&ybDlc&8bdj6+IyZNzZ_|E+%%rzbAWTTS}K8?BuI`EWyC^y z*|jqnT|P1Gvk5K_EkmJ?7H#%-y-bEC9&>hZ$_iA9n9Nn|yRO)G73RF|Q|P$Lly9pyF2K8Hk6Ok8wIeyC6=(wrdw)yLVEQa>uXOTyc-3p4-jhUgP)x}q zYIOd(AeV%LkEy2%WZNR9=WC(Pf4N|@-Ooci`TOagaL)^KjMVe|C%?^I2Ul3a?%yu6 zU=-|@+<{iI>YCUFD;fYLvY8sRm!rX2JuNB)58&#tU}-lk(DbD7$hj=d*(hj0(Ae?n^ioXU~^PiJlag_ZNaBeVVit^S`8LDHA%{~t}QBV?0>FkJ%*#lfU8pM9N@_v z6yuR{?jp<8Hc>%tO%I*KSx1bQ5r<;u8@ZQt)YaA3!0jhs!NIkHMGB#Yo&qbcy*m4~ zn*M;8B?C0C30t1=(hR*Xc3!g}E4E*jRhaXwj&?gJZq!ncB0ONY}m zy>)ShyoOi=sJn3N8?h~kV*OIsI|-^WJ4fkDnq`fj_TaAkp2VmQ z{MzQlhrKV1zT~)(ndk19G`{;>1=7M(cO$k%x2L|DW|OhTVv~@3O^|(~Mj~5#v-#kN z$sPEtgkqV$(uBpRgQmbv7O}LRy|!?|SPF;xlgH6F&{mHEk80xYDVb|k9NP-?MvixAT78tPn1R-vu!3obbe>JE6o@bMn2bY( zW5UgWE18z+u!>|SPceM^;R}`V+dF#xvlci39IEFqIl9IDkzJCuRvMs42k8E&S<7NH zDkMzSWu^Xr$~9@_5xS~^MUA2`VK;tG$^G(?2Ux3DvY*2j87HKi2dIpu7?%G*4uAL1 zMp_@>pxd?f@h@NJEN%AFBK@=CeOjFwh_|Qk%o)%|aRo$=ihbInT#Zc#_(TS zM(FyJ7k#kx%Law$Q++0wRT0AW2D`STEGDwowk9riQtf4lyy;g%PcPg4`p!J1bo@iC z!1Y3=o2vbWg>$ba`A^D`#DjhXW9KDo(~4+S^=JurCIqFE$_j@L$q25n+SW{=G$yJ7tO1_ z4R-jm%9zerk-op5_c^nJjNWRtSM1Di06_1@UN8a+9}T?_h5LVr zJtcs@9roo{%P^g46nn=4C_9KLc@0H8krR}u1$a3fP2ut8`-1kH19kV0@2%@bFhWYYu+WctlRMf09gESYh zsnc;t^xiS&GE)bLjiz}AnB`i|cclI~377X1eWi+7S*AW5W1C`sYr#wWhq^aLc=Xwv z<=!V0QsjuYo6%gQV!sufOtiVfTVlp3+>icKS>h!=mFTgG4oqyd1nxU-^#(^8YmE#* zM&bOw=z&st9uRx7!;qaswTSR)rcYi~+wKW_E?8?H{xF#&^DiW064^95vUWCCWr z@Z;eiX2J8LaK_S(#cIJ@Iw%xb#dW_yFJxl&OoLh7h9uO8HxGgv8M*XLvP5SGEX@O1 z!0P5F_SguHGLAT>EYN;dT}40oxyXkQ@TgeGlOHwId&afo=Y=nd+$pm2NVfLAd00x_ zuaQ=mMhEq;W!#2c5ry%a7ImxY7}{ZT3H|L|R4pXAKc`+FCC6a%f+Kx%8<#20er}KZ zEg{%bgJHB<4e&V`J^!B8m1NLnce4=VID2shQM{m^YSVCz`57%b8gnUPZVZtlKQp3l zZlmwifO%HWn1H`--;TD31;<_NIW?G7K^9%8K35KF-^P_&C3dv5i!>>ABT%Rcl@ zD)0VYyxNUdn9Zunb3c011~E}* zPc3nDc^uAXd5+V~AIos|iBjO!SCBByvG`r4S;UnoFjdGHppZC%7w~+YYtK&}BSFY- zik|>1`8(PKIfQPdQ?hn%rRW2-Jen10kLEv@D1lvi z5^Z)!`ImX6jx63Yf?B&w_G*Qf5*#6LxB8xwW} zb3Q!>Gs2T-hTbjyjvK%?L82p6Y_BfepweD@bZ4vl=bZGxJ$bV}e~DQs=|T#(&j$=a z3_u`;pz+pKE-vDwlFj zh>(ssPTJ+qwlAIM#=*!OSJDzb@}NSMYeozNk>WCmMHjU#CI@NzLZLSQRnwmc_}T(Ha6{0e*CtQs$0R^ zj>+^5-x%*FcnT&hGtpzkrP%Oee;mlfA{I+3u_2pbYLFWfdlA(>^VSi`3u!PHnu6BE z`&|4Cvgh?Zz4rhh?BE%gMT-^Q&VD&2f9iQcv|H~4*mfzmn1my7yz61_Qwausqw4^k zzx=RqpA0w-%?Ssp`FWBZ2IV-3Q?xcMEQ3gxP7q}mb-I~RLWs8Smc8bl84fc)j?A!p zM!$kZjbwpC{kEN0Kul#SCx(RBBen_C=272uIIs<|w_9aJX>*6dsKv5sHP3L9}Zt+L6;|F9dfxNMcE1-}?%9DeYmCfSq!j$FBHm}(Y2ciPa_4QYP- zMyo__R9~GTR}W&o4FIQgf>`@_0Mb>~OAwa3wV&6IoM(UgR6M*AX71ysjBeF1lm9~@ z!#C=9-~A1iakr`TGPtkkyNpNAr+XES!$!6hAMW@U%OC0&FoHbfn8#`RFxP;{%5+>Y z2|YO|Qor)d7ui;3e*E*f$Kihk0|34n|FCj=r!fL-nm{N^T4^^3RXa5*{Mwo(3UI4v zTwEGM2CTL$h{H2$79M<$+PDR`rg1`W4+M7!?(QzZEx0riw6WmcOvCS- zGjrG6b=SAPnRWZGdf%$IYS*r+y>~tP=};vFX;frFWH>lD)K4-JDsXVG-QeKh1KzxZ zy@}f!DY6w?awHDw5J^GC<@b)ml*8k$15SNNlXXzxDec z)nyy&SKc0_?h}z!IG%$(JX5W1c_-I4I{Tc}Zxx##u9V4URrXf>TaD=i{c5w$4^#SmXBxX)Sw2II$Dyw{n}QddV(IIWrX`K`+cJg>%YU%{k;gA)lU zXutS!${vmJ{0N8fVd9?xxp>x#=aPhZDgKO)Yr}4^=d7oX^*z$_Tg)6u_~$|hiXXyr z0XnRgDnAlL~qGjOUK=9Sks|ebn_1Qk2{plKvu|>}I|u zcWFmKAeaxx_7#`Rpx*XTXUL$W@=hy~n`%${v7pi7l^xkrTf>R8IlrK5 zaWSdiRZoIt(~Mx^5tYG1={yudG@)cZpl;zmy#iI|!lB8DVQ>4BoLxI8d>W_?6?&E{ z!X$6Vozrgb_kL{%LlX1*0|Ma9kIH_0t zmJas^c4v>uw2#HyLxy*0G>uZrPDK|xi4slBLu)BDe~%?aM>fALf4!;5pe&C9bO)Bx z_>7+V4e*%5|c|LNndK$5ZD=3v$Qr%QyFsPNmup&d11NP_mE(%dB(gdLU`?+Jeh zQA3Xi&zADo)BF^dbR|YTPS#{MguyjbdErFu*foDU!nh-N4R8+M^E)GG4vdG)U4|ge zg-bssx*eBVSCP*%XJ~#ptcM;56++b>sB+A0Y)19z6-`Umoi~18_2wIdd-^a!dwiDq z`b1w~KglAad{>lJR4}5y9)b*@Mi@fX*2wk0>di&nrhy;rnDc&hKJXfgnSG~~uIK(Q zSox%)V=l9~x8ouB+A)U5S*(^Aqs91^XMp!T=e7+NP_<9|=0s)c6j2$ZNa&F0_{^RPz355t<5KBb{3hVZBFzEi*dlK@|xsWXd_kCR-sEnPzIh1<#PZo_;x zWPPz8uin2lPB(z<-CSWQ`rmeW4n=M>mHhpb#qwSBuZ_RWl>RIkzBm*;@%JZ}(`-0v z+9?g$DYc30q11zD z@V<%{nxKII-u070qt2!+Sr=`V}IYj=gE9LqH?^* zGrxVy^pEYSjSXd+NB*%d<@Y?>hh1XF@&{TdnNB$y{SuxYon6zXtC~Ao(mKL~kMYEJr|5ydez0!@TJ+M3vY(%apq-7L57Vr{H$0o(PWSL~ zEco5QbYuC@fqT6XJc~Xe&%U>=7Gc8S&BMLI_E+s@JO0& z?UQxSoEzUzyhQ=_`g_Hy?If++%-#{%zSmNqgpRN)Fis1Up}s!!gYp%k;|Wm1!?ao$ zJ2PnfKKyV)yeV0G!btVgyjp+ zUCl`sRP%OuM~M27gxx&ip6ro?-?jANI9^jf`5w|gv|92QK|=5U_VgE9BUwS(Ohjl^ z6#@lGFWx_Wh#o+^Y~n-_UPbt#N|km&(}q5~WQj7#_TwE;E}{|~(D=7}fd7}9lp+UZ zb*1qym3O`S^zlpS zq;R)>@JiZ;dPe`_f1EFVs22t28_gDkRX0?G7~~qs9_{e^gCh>35mO0ruMY_1@16yW zAZxEjl9FGIqPXT$npX~r)8)Vy7e-#;=nmn0W8Z;f#98vU&5eA9^Lcr`e%LITTxz2Z zXpr=;^iXUR{%Bt+*y&&8^2fi@81?8U3*SG3QvlXlr~`1U(OKn*RO}`VqsI(u6IpKM z@mFtBSgwT%n!r7@&%<|CVr%(=g3-J%5L;R#gmX~3Ehi022akx2T0i_=N$cVk@fYlP zZV5*rVFLuOc!~uy*r6BUTR-;WpC|`#nEnmq{->t_v$@+9ah6^#Tl6Al9S;1C27aY$ zLbgT<;^%t9pJ#PuEYR~vbXpaAXO`IpY!G)?ZIY%AvXtpR4FbX=NqXD;$Zf^~`VrbC zRd*5I9nB-y*F8r=hH;K_Co3jA2xH%WRv8&ZI2-)4weUragMAJZvp!rVqWt^u z$o%9AGDAPdHqDD`y&XPCnfO!9(#Fs`fl0ye&lFxBXDvPBbd+6 z&*f4$LRqPvdxI~is5tHo#loUih{Hg11QU${s1-7WKxh-cz3$|5CQ+0Hqu1J;!RDSs#WB*UGS-8~uMC(f>Wn4Ep!P z{u59VyhLS6zu4;Y*-C9*sW~WD{te-W_t9E8NF7~=(up|NSsbOT82?mW^3?Qh*lk#u z**SMk{+g8jtYLiQSA_SUN$s4pQ)|i@^0!xYba4tamI1z+j%J>cZEX>eI3y+aFWy=l z$#3KCI?rj=YG&x>d2cQNR2OK*M4f?V&u$hD1@RT(Myh6A6?sSY)au9VGFPC? znurS*XYH1zTB6yaYW1*{#%4qL68f}KcFSJ;>^%;r*}`SqNHrwvzJ3w)gh=#RBPwn(RR5K;xasX-2Z&#gUXPJP zO*JIt_O>MgjLTetmXUy0Y!tW>(LEF2Gt-yVq{CF%-ruqLk$1SYq`jvDykg$%C41?j zPz1IetyrX}ok>{u;yjL9qulciI=iruWo1Ju6}1G zBuuMt=?R;Xbgx`K z;EJ_xfPP>1H>=~-7>}#Vi;TA_VITHk5-#~G@2#3{wUBLrMGrCIiyfd5*S0NhB9TW+ zUPfy3#nvr))4p~#%eY_e>hf$T**%CE z(pO#EWwSFj7XqtiS>TDbFXFj0+ASU#oHfV}HV$I=l*47k!0r1fugQ7C2iGh1x-$2? zzGiTHwrHGyOb50S+z}f3mSlR{lLVbsE)xGl@e83!BdNE z9wJiwl?mF4Le_@il^BUS=s?HNt+$c-4~(Sel}Dj|MR+?{2;eS9Mj;>2^1qn|JT7Qy z6CVRGi-*cGPg0#LoSJbs+NS6}%K~EHR$gw%mjETfa@4P40eW=5YkIVXkAe_le8sCu zOF_prmN=Aof#s46G>)7T1A}|g06-wh^6<#W;Dy(50Q_>S)&Ba=<(~~De`G+IWx~%A zh})NnkgrIamI>5vmy*_VGnAB-(%Lq&Zze*DJmXpT32h2Hob{Kf|DKIBrIv(ia@x(; zdVy60o3g9tuRaG(b!J+?*4v<^+~^A8ewIQ+DCyJZ)l$zyLDJs97Z>7;p8BB}^vSb( zbr7{Q(_K@$3p%+mE?E1Gr#UF9QVjNd!6{3pC!MG zuX>vogSP3aa+NpLvHADuw21_;&3FWrzHt_t`SeLCQU}hrf20eSD3Xzj98k&^+I@ki z5kJ0+Kk@LvSJHdl@~xEw0*UV)_#?%;_$|#DcBW^`ibC&_F4K!2Z7Av>2mobSmI2J> z1}|Fhzb#$vj7QkwOzIuFqXu}|&D@EAK3N_+Fpi!vAqoF^O~7Bg(uU@ul$G04hkTI| z6wrotp32O?TJ<$8`RIgflbj!u+v0BwMsVFS#(C7gu>i`P8TS7Cs$BuiRdmTV7YbJf z6aq&rT}bM)4P}9C?%swL9ijP#U@nv_X?mB3GD2q9p>~%xRe~o@U_#sF&W631WjcFz zKGB+8KT5o%90}dk(YeZ>xzzNVzJ7}u8QJZ%8lW#Zv#2sh$G5LpVa-U(%wJ#*CneEC zm?>637i!?1OV`hnmy8$O5O&6!^EYl=hQh+rwPEJg3i+LSVfm}R)FDCVl0@yr3yX_)Z<#!OAG@V(t}huFVfN8xT1ji>+yQvPX5#fa+tV~@ zDJO@0czWP1pRE~?Nb-iwIw`0%%;Rhen~uIXJbj&Lvz(P%qR)EBYAcqY?%87n=`1F* zTl88^&&|y(EV%dKXg-?=I0W#LeMdU%mykd;X77^zG#@y)nE#>=dT#vRb!H=4ti^2) zmrMV6eUt=cQp8P*h0g zyI2o?e|d2c8bij&c(@VHOe*Yi4~ru{!X#vIf`!*#Cl#d#nwy)cP@+^+QkvAs+U@SHJ&C*#Cd3w+Niw2KbE( z0GM{qcvK~ZR%NzLwv?Cf@6wz;CQ$7DfQnTqDjd-O+u0sBoI1SgWYc33lfCNRj#V=P zQ#q~wbOx>C zEXu@7gv$E#pdLvy3!z=UAbNfEWqA$kb#oZQ?CC6i>~W<%sS45KMtG6O>OFB)N>AzN zYCUiJ>Cs$42}Ol@{gf=-ocMFkT^KJ1;xXJC29`;^SSeZD7a@{a>&tHT7@K)6qf`os zCti1UJs_@_=Tnh0iqKt{H>f=wDda=9>Y%v(Dz@QB2 zH*BLvS!awC2QK~nR?1->njjo{q>WL^S0i)JaD)P{g(5X!#2G88YY3M{{f0y0lm6!x z?$83)WROXJS-~LCeqCVZ3hdBY`KfldfTo>#{qp|km)#fz-j&!l(xO3Ka6v%h##fyX z$1_uE8{-6gF()h?Q=Bodisr^4WBjKTKCoPChxxh{?XadR$lApLXw> zX2BJYWp{|NFsa^Vn?HAc%hg@XT(6+iy5pP^KwFLFm12FL^`Y^Gnq#;UT1B(ux0c9x za){4ucDsB-Soui6YS`VmIl_CAay>fyDKYxdbh`R<^*$CweE6{qLPx=xL)nkMwhEeSI{Xi_GkTJJObOyWb z3w`vM>eIX9VAEdarZ4>a{;vcJO$xtf2Q2a3yGh886_fUxVpp+(w5-enBK8c<&@<3Jca|qRoF|@K# zu0D*d@g-t^q^OpI>ycj7g`}ezirv=X*Y@i%9QzI$ef}f+F%x~;L-sPJgz&PJ;>&Bj zom%r%b9_cZi2;4r2FnmlHy6JJc6}UwQj?DGud)SI0SS1081ACUyS$~w<2{bZ;0dQh z2LpH-6HmNB)h=bt;jHqcWJGy4Ka9g!+fZ)u_YR`x8E~WIG5oJ~xZ(VRSP99g=syTH zW9E!y7tF9nX0DXIcLWvP>0}=lZnEEJ?(LlpU1gEreNXIUPG!F$R;p7~O)O3&_}$QE zslZMDWmatSH?O2Y*_PRS64U-iAanBY_qS>J1*ysi^hVB#{By^mR6nwH);vol%r^kK z5QX~`?HoxkWG|ErQ9sqn?u&b~N4E`wgns?-u`BLr3O>WHKI?+MWdd;M?Wb@Ov&Ni( zMYBB!l2t>-)~7ia0!8AE&J{AXE}_{Mi^^3r+jaw%sV2wL zca86sI>OYq4{5{?>WM%({R+%@FIJ)uma7E$qj3S;ntE3=MlU>Z@*)e@#g(6PkazQacXC?*xacK2S>Z*9U#tnl%iF zV5bgm+S{lTA9L9epkihPv)ck%c)g7i8>Rb6O05@W0j#oUi^KI_b+eLQ{&worYsWAP zX>;+>U0omeQNX-N>Pi}w`SZiNP{XiiYV(CTlJAryUQx|$9sJnHrEO}8`w#a$Vh*F% zQdWD_3=~Clx?Xk4QYvHi-Wv`#%y5_v>@2lY9 zv}f~N5}JpKRqtN_Bpd9E@OT<2WX6#0g24k9C#IL8x zt=@ozTWXw3E-Yc$IEzr*OK-CTUciifq^{t~*GD1xeNzoQm%e4b-DUjNeU0d5;V~4? z?R<)Nmy9tHQUseT;^A$p7o$G}qXF^pcav`bgA7hia>9noT#XH2DJyl+6b4+2K7gkT zMtUl}$GNyN0lynRAl{im=Y##I*}WK}@bKV^8~UcSxzga0%SmOSYeqtal3>Owt;fVv z*IuGbcBg)(?^0zKb&YqLxQU1$-tjLz^#FC9(%{14wD7L_oxssw$Q7!i_}kFmwyGdo z=nU&lOHqUOs$~+3*`RHp@!b1T8j1C*5mH4n>aMc}p^Wpd#E3nmFD>=e> z%-+Oq)gt*s-uXCqc@>n2i}foUyI0V^kMvHQ%&Vto$V%lKlk;h8?XLAK<=${t=*%`Amyc7e8JEdhiU6LWb*D z+a7S2z=j8D>2GEAqT+3=OFBtTT~xY}58D+rt?R%%k5?15BC|jLT6lp$M5)^`rsumt zSDN;-dJiin4mTuPNfj@Zw%2UeOzD2zV?8}F#|m<*D@glOdrk9uN2I5Q3|jUXtOy-M z%36M`a%W)0Au@&SH;Wi>2>5@s|amx2R6�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 S#A5MHP-!XDT{Wab7ybp#CXWmN literal 0 HcmV?d00001 diff --git a/docs/screenshots/settings-software-update.png b/docs/screenshots/settings-software-update.png new file mode 100644 index 0000000000000000000000000000000000000000..061d408a93fff6947c8ee07180dc38d48ba7956e GIT binary patch literal 27863 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 F{V(yi#)tp_ literal 0 HcmV?d00001