@@ -3,7 +3,11 @@
|
||||
|
||||
package updateserver
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGIT/modules/setting"
|
||||
)
|
||||
|
||||
// Update-feed platform identifiers. These are the recognized values for the
|
||||
// UpdateStreamConfig.Platform column and for the resolved "RepoUpdatePlatform"
|
||||
@@ -29,39 +33,87 @@ const (
|
||||
PlatformMCP = "mcp"
|
||||
)
|
||||
|
||||
// feedlessPlatforms are platforms that never emit a legacy update feed.
|
||||
// feedlessPlatforms are the statically-known platforms that never emit a legacy
|
||||
// update feed. This is a back-compat fallback for the registry lookup below: the
|
||||
// authoritative signal is the platform registry's feed_format == "none", which
|
||||
// also covers "go" and any admin-configured feedless platform. See #811.
|
||||
var feedlessPlatforms = map[string]struct{}{
|
||||
PlatformNPM: {},
|
||||
PlatformMCP: {},
|
||||
}
|
||||
|
||||
// IsFeedlessPlatform reports whether the given platform must not serve any
|
||||
// update feed (npm / mcp). These repositories are published to an external
|
||||
// registry, so every Serve* handler returns NotFound for them. See #810.
|
||||
// update feed. A platform is feedless when the platform registry gives it no
|
||||
// wire format (feed_format == "none"). In the built-in registry that is npm /
|
||||
// mcp / go (npm & mcp publish to the npm registry; go publishes via git-release)
|
||||
// plus any admin-configured feedless platform. These repositories are
|
||||
// distributed through an external channel, so every Serve* handler returns
|
||||
// NotFound for them. See #810 / #811.
|
||||
//
|
||||
// Note: feed_format (NOT update_generator) is the authoritative signal. npm/mcp
|
||||
// carry update_generator == "npm" (their build/publish generator), but their
|
||||
// feed_format is "none" because the update server emits no feed for them.
|
||||
//
|
||||
// The registry is the single source of truth. The static feedlessPlatforms map
|
||||
// is only consulted as a defensive fallback (e.g. for a key unknown to the
|
||||
// registry) so a bare "npm"/"mcp" is always treated as feedless.
|
||||
func IsFeedlessPlatform(platform string) bool {
|
||||
_, ok := feedlessPlatforms[strings.ToLower(strings.TrimSpace(platform))]
|
||||
key := strings.ToLower(strings.TrimSpace(platform))
|
||||
if key == "" {
|
||||
return false
|
||||
}
|
||||
// Registry-driven: feed_format == "none" means no legacy feed is emitted.
|
||||
// This is what makes npm/mcp/go feedless from a single config source.
|
||||
if def, ok := setting.GetPlatform(key); ok {
|
||||
if strings.EqualFold(strings.TrimSpace(def.FeedFormat), "none") {
|
||||
return true
|
||||
}
|
||||
// Known registry entry that DOES serve a feed (joomla, dolibarr, …).
|
||||
return false
|
||||
}
|
||||
// Unknown to the registry: fall back to the static feedless set.
|
||||
_, ok := feedlessPlatforms[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResolvePlatform determines the effective update-feed platform for a repo.
|
||||
//
|
||||
// - If the update-stream config sets an explicit platform, that wins.
|
||||
// - Otherwise the platform is derived from the repository metadata platform
|
||||
// (metadata.platform), so the two stores can no longer drift. See #811.
|
||||
// - Feedless metadata values (npm / mcp) are propagated verbatim so the
|
||||
// handlers can return NotFound instead of falling back to a Joomla feed.
|
||||
// - Only when neither source is set do we fall back to the historical
|
||||
// "joomla" default (used by legacy Joomla extension repos).
|
||||
// Precedence (see #811 for why metadata can override the config row):
|
||||
//
|
||||
// - If the repo metadata platform (metadata.platform) is a registry-recognized
|
||||
// FEEDLESS platform (feed_format == "none": npm / mcp / go, plus any
|
||||
// admin-configured feedless platform), it ALWAYS wins. This is the #811 fix:
|
||||
// the update_stream_config.Platform column is `NOT NULL DEFAULT 'joomla'`, so
|
||||
// any licensing-enabled repo has a config row that resolves to "joomla" even
|
||||
// when it is really an npm/mcp/go repo. Letting a feedless metadata platform
|
||||
// win means those repos return NotFound instead of a bogus Joomla feed.
|
||||
// - Otherwise, an explicit update-stream config platform wins (this preserves a
|
||||
// genuine, deliberate override such as dolibarr/wordpress/etc.).
|
||||
// - Otherwise the platform is derived from the repository metadata platform, so
|
||||
// the two stores can no longer drift. See #811.
|
||||
// - Only when neither source is set do we fall back to the historical "joomla"
|
||||
// default (used by legacy Joomla extension repos).
|
||||
//
|
||||
// Joomla-preservation reasoning: a genuine Joomla repo has metadata.platform ==
|
||||
// "joomla" (or empty), which is NOT feedless, so the config platform still wins
|
||||
// and the Joomla feed is served exactly as before. The only behavior that
|
||||
// changes is that a repo whose metadata says npm/mcp/go no longer serves a feed
|
||||
// just because it carries a default-'joomla' config row.
|
||||
//
|
||||
// This is the single source of truth for the old "empty ⇒ joomla" fallback,
|
||||
// which previously caused npm/mcp repos with no config row to emit a Joomla
|
||||
// feed. See #810 and #811.
|
||||
// which previously caused npm/mcp repos to emit a Joomla feed. See #810 and #811.
|
||||
func ResolvePlatform(cfgPlatform, metadataPlatform string) string {
|
||||
meta := strings.ToLower(strings.TrimSpace(metadataPlatform))
|
||||
// #811: a recognized feedless metadata platform overrides the config row,
|
||||
// including the default-'joomla' row every licensing-enabled repo carries.
|
||||
if meta != "" && IsFeedlessPlatform(meta) {
|
||||
return meta
|
||||
}
|
||||
if p := strings.ToLower(strings.TrimSpace(cfgPlatform)); p != "" {
|
||||
return p
|
||||
}
|
||||
if p := strings.ToLower(strings.TrimSpace(metadataPlatform)); p != "" {
|
||||
return p
|
||||
if meta != "" {
|
||||
return meta
|
||||
}
|
||||
return PlatformJoomla
|
||||
}
|
||||
|
||||
@@ -78,13 +78,14 @@ func validateUpdateKey(ctx *context.Context) (allowedChannels []string, ok bool,
|
||||
// ServeUpdatesXML generates and serves a Joomla-compatible updates.xml
|
||||
// from the repository's releases.
|
||||
func ServeUpdatesXML(ctx *context.Context) {
|
||||
// Only serve the Joomla feed for joomla/both platforms. The platform is
|
||||
// resolved upstream (config override → repo metadata → "joomla" default),
|
||||
// so an unset or feedless (npm/mcp) platform never reaches the Joomla
|
||||
// generator. Any other platform — including npm/mcp — returns NotFound.
|
||||
// See #810 / #811.
|
||||
// Registry-driven gating: serve the Joomla feed only for platforms whose
|
||||
// registry update_generator is "joomla" (plus the "both" compound platform,
|
||||
// which shares the Joomla + Dolibarr generators and has no standalone
|
||||
// registry entry). The platform is resolved upstream (metadata feedless wins
|
||||
// → config override → repo metadata → "joomla" default), so a feedless
|
||||
// (npm/mcp/go) platform never reaches the Joomla generator. See #810 / #811.
|
||||
platform, _ := ctx.Data["RepoUpdatePlatform"].(string)
|
||||
if platform != updateserver_model.PlatformJoomla && platform != updateserver_model.PlatformBoth {
|
||||
if !updateserver.PlatformServesGenerator(platform, "joomla") && platform != updateserver_model.PlatformBoth {
|
||||
ctx.NotFound(nil)
|
||||
return
|
||||
}
|
||||
@@ -117,10 +118,12 @@ func ServeUpdatesXML(ctx *context.Context) {
|
||||
// from the repository's releases. Uses the same license key validation as the
|
||||
// Joomla XML feed — all platforms share the same licensing system.
|
||||
func ServeDolibarrJSON(ctx *context.Context) {
|
||||
// Only serve for dolibarr/both. Feedless platforms (npm/mcp) and any other
|
||||
// platform return NotFound rather than a feed. See #810 / #811.
|
||||
// Registry-driven gating: serve the Dolibarr feed only for platforms whose
|
||||
// registry update_generator is "dolibarr" (plus the "both" compound
|
||||
// platform). Feedless platforms (npm/mcp/go) and any other platform return
|
||||
// NotFound rather than a feed. See #810 / #811.
|
||||
platform, _ := ctx.Data["RepoUpdatePlatform"].(string)
|
||||
if platform != updateserver_model.PlatformDolibarr && platform != updateserver_model.PlatformBoth {
|
||||
if !updateserver.PlatformServesGenerator(platform, "dolibarr") && platform != updateserver_model.PlatformBoth {
|
||||
ctx.NotFound(nil)
|
||||
return
|
||||
}
|
||||
@@ -153,10 +156,12 @@ func ServeDolibarrJSON(ctx *context.Context) {
|
||||
// ServeWordPressJSON generates and serves a WordPress PUC-compatible update feed.
|
||||
// Compatible with the YahnisElsts plugin-update-checker library.
|
||||
func ServeWordPressJSON(ctx *context.Context) {
|
||||
// Only serve for wordpress/both. Feedless platforms (npm/mcp) and any other
|
||||
// platform return NotFound. See #810.
|
||||
// Only serve for wordpress/both. Registry-recognized feedless platforms
|
||||
// (npm/mcp/go, feed_format=="none") and any other platform return
|
||||
// NotFound. See #810 / #811.
|
||||
platform, _ := ctx.Data["RepoUpdatePlatform"].(string)
|
||||
if platform != updateserver_model.PlatformWordPress && platform != updateserver_model.PlatformBoth {
|
||||
if updateserver_model.IsFeedlessPlatform(platform) ||
|
||||
(platform != updateserver_model.PlatformWordPress && platform != updateserver_model.PlatformBoth) {
|
||||
ctx.NotFound(nil)
|
||||
return
|
||||
}
|
||||
@@ -200,10 +205,10 @@ func ServeWordPressJSON(ctx *context.Context) {
|
||||
|
||||
// ServeComposerJSON generates and serves a Composer packages.json feed.
|
||||
func ServeComposerJSON(ctx *context.Context) {
|
||||
// Only serve for composer. Feedless platforms (npm/mcp) and any other
|
||||
// platform return NotFound. See #810.
|
||||
// Only serve for composer. Registry-recognized feedless platforms
|
||||
// (npm/mcp/go) and any other platform return NotFound. See #810 / #811.
|
||||
platform, _ := ctx.Data["RepoUpdatePlatform"].(string)
|
||||
if platform != updateserver_model.PlatformComposer {
|
||||
if updateserver_model.IsFeedlessPlatform(platform) || platform != updateserver_model.PlatformComposer {
|
||||
ctx.NotFound(nil)
|
||||
return
|
||||
}
|
||||
@@ -240,10 +245,10 @@ func ServeComposerJSON(ctx *context.Context) {
|
||||
|
||||
// ServePrestaShopXML generates and serves a PrestaShop module update XML.
|
||||
func ServePrestaShopXML(ctx *context.Context) {
|
||||
// Only serve for prestashop. Feedless platforms (npm/mcp) and any other
|
||||
// platform return NotFound. See #810.
|
||||
// Only serve for prestashop. Registry-recognized feedless platforms
|
||||
// (npm/mcp/go) and any other platform return NotFound. See #810 / #811.
|
||||
platform, _ := ctx.Data["RepoUpdatePlatform"].(string)
|
||||
if platform != updateserver_model.PlatformPrestaShop {
|
||||
if updateserver_model.IsFeedlessPlatform(platform) || platform != updateserver_model.PlatformPrestaShop {
|
||||
ctx.NotFound(nil)
|
||||
return
|
||||
}
|
||||
@@ -269,10 +274,10 @@ func ServePrestaShopXML(ctx *context.Context) {
|
||||
|
||||
// ServeDrupalXML generates and serves a Drupal update status XML.
|
||||
func ServeDrupalXML(ctx *context.Context) {
|
||||
// Only serve for drupal. Feedless platforms (npm/mcp) and any other
|
||||
// platform return NotFound. See #810.
|
||||
// Only serve for drupal. Registry-recognized feedless platforms
|
||||
// (npm/mcp/go) and any other platform return NotFound. See #810 / #811.
|
||||
platform, _ := ctx.Data["RepoUpdatePlatform"].(string)
|
||||
if platform != updateserver_model.PlatformDrupal {
|
||||
if updateserver_model.IsFeedlessPlatform(platform) || platform != updateserver_model.PlatformDrupal {
|
||||
ctx.NotFound(nil)
|
||||
return
|
||||
}
|
||||
@@ -298,10 +303,10 @@ func ServeDrupalXML(ctx *context.Context) {
|
||||
|
||||
// ServeWHMCSJSON generates and serves a WHMCS module update JSON.
|
||||
func ServeWHMCSJSON(ctx *context.Context) {
|
||||
// Only serve for whmcs. Feedless platforms (npm/mcp) and any other
|
||||
// platform return NotFound. See #810.
|
||||
// Only serve for whmcs. Registry-recognized feedless platforms
|
||||
// (npm/mcp/go) and any other platform return NotFound. See #810 / #811.
|
||||
platform, _ := ctx.Data["RepoUpdatePlatform"].(string)
|
||||
if platform != updateserver_model.PlatformWHMCS {
|
||||
if updateserver_model.IsFeedlessPlatform(platform) || platform != updateserver_model.PlatformWHMCS {
|
||||
ctx.NotFound(nil)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user