diff --git a/models/licenses/license_package.go b/models/licenses/license_package.go index 8672479d52..2f5c1916bb 100644 --- a/models/licenses/license_package.go +++ b/models/licenses/license_package.go @@ -32,6 +32,10 @@ type LicensePackage struct { // AllowedChannels defines which update streams keys from this package // can access. JSON array, e.g. ["stable","rc"]. Empty = all channels. AllowedChannels string `xorm:"TEXT"` + // DomainRestriction is a comma-separated list of allowed domains. + // Keys generated from this package inherit this unless overridden. + // Empty = no restriction. + DomainRestriction string `xorm:"TEXT"` IsActive bool `xorm:"NOT NULL DEFAULT true"` IsArchived bool `xorm:"NOT NULL DEFAULT false"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"` diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index eea2aab73b..b9315a029c 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -421,6 +421,7 @@ func prepareMigrationTasks() []*migration { newMigration(341, "Add parent_org_id to user table for enterprise sub-org hierarchy", v1_27.AddParentOrgIDToUser), newMigration(342, "Add is_hidden to repository for three-level visibility", v1_27.AddIsHiddenToRepository), newMigration(343, "Add custom field tables for issue custom fields", v1_27.AddCustomFieldTables), + newMigration(344, "Add domain_restriction to license_package table", v1_27.AddDomainRestrictionToLicensePackage), } return preparedMigrations } diff --git a/models/migrations/v1_27/v344.go b/models/migrations/v1_27/v344.go new file mode 100644 index 0000000000..888f32760c --- /dev/null +++ b/models/migrations/v1_27/v344.go @@ -0,0 +1,15 @@ +// Copyright 2026 Moko Consulting +// SPDX-License-Identifier: GPL-3.0-or-later + +package v1_27 + +import ( + "xorm.io/xorm" +) + +func AddDomainRestrictionToLicensePackage(x *xorm.Engine) error { + type LicensePackage struct { + DomainRestriction string `xorm:"TEXT"` + } + return x.Sync(new(LicensePackage)) +} diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index 1ca87c1d1e..ba4bb55cdc 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -2668,7 +2668,8 @@ "repo.licenses.licensee_name": "Licensee Name", "repo.licenses.licensee_email": "Licensee Email", "repo.licenses.domain_restriction": "Domain Restriction", - "repo.licenses.domain_restriction_help": "Comma-separated list of allowed domains. Leave empty for no restriction.", + "repo.licenses.domain_restriction_help": "Comma-separated list of allowed domains. Leave empty to inherit from the package default.", + "repo.licenses.domain_restriction_package_help": "Default domain restriction for keys generated from this package. Comma-separated. Keys can override this.", "repo.licenses.use_package_default": "use package default", "repo.licenses.expires_at": "Expires At", "repo.licenses.expires_at_help": "Leave empty for no expiry (lifetime).", diff --git a/routers/web/repo/licenses.go b/routers/web/repo/licenses.go index 5182ef3257..f3b4c0f7f5 100644 --- a/routers/web/repo/licenses.go +++ b/routers/web/repo/licenses.go @@ -187,15 +187,16 @@ func LicensesCreatePackage(ctx *context.Context) { } pkg := &licenses.LicensePackage{ - OwnerID: ctx.Repo.Repository.OwnerID, - Name: name, - Description: ctx.FormString("description"), - DurationDays: durationDays, - MaxSites: maxSites, - DomainLockHours: domainLockHours, - AllowedChannels: allowedChannels, - RepoScope: repoScope, - IsActive: true, + OwnerID: ctx.Repo.Repository.OwnerID, + Name: name, + Description: ctx.FormString("description"), + DurationDays: durationDays, + MaxSites: maxSites, + DomainLockHours: domainLockHours, + AllowedChannels: allowedChannels, + DomainRestriction: strings.TrimSpace(ctx.FormString("domain_restriction")), + RepoScope: repoScope, + IsActive: true, } if err := licenses.CreateLicensePackage(ctx, pkg); err != nil { @@ -270,10 +271,19 @@ func LicensesGenerateKey(ctx *context.Context) { return } + // Domain restriction: use form input, fall back to package default. + domainRestriction := strings.TrimSpace(ctx.FormString("domain_restriction")) + if domainRestriction == "" && pkg.DomainRestriction != "" { + domainRestriction = pkg.DomainRestriction + } + key := &licenses.LicenseKey{ - PackageID: packageID, - OwnerID: ctx.Repo.Repository.OwnerID, - IsActive: true, + PackageID: packageID, + OwnerID: ctx.Repo.Repository.OwnerID, + IsActive: true, + DomainRestriction: domainRestriction, + LicenseeName: strings.TrimSpace(ctx.FormString("licensee_name")), + LicenseeEmail: strings.TrimSpace(ctx.FormString("licensee_email")), } // Auto-calculate expiry from package duration. @@ -500,6 +510,7 @@ func LicensesEditPackagePost(ctx *context.Context) { pkg.AllowedChannels = "" } + pkg.DomainRestriction = strings.TrimSpace(ctx.FormString("domain_restriction")) pkg.IsActive = ctx.FormString("is_active") == "on" if err := licenses.UpdateLicensePackage(ctx, pkg); err != nil { diff --git a/templates/repo/licenses.tmpl b/templates/repo/licenses.tmpl index aebd76106c..41b6db02f9 100644 --- a/templates/repo/licenses.tmpl +++ b/templates/repo/licenses.tmpl @@ -76,16 +76,14 @@ {{if .IsActive}}{{ctx.Locale.Tr "repo.licenses.active"}}{{else}}{{ctx.Locale.Tr "repo.licenses.inactive"}}{{end}} {{if $.IsRepoAdmin}} -
- {{$.CsrfTokenHtml}} - - {{if $.IsSiteAdmin}} - - {{end}} - -
+ {{if ne .Name "Master (Internal)"}} {{svg "octicon-pencil" 14}} @@ -311,6 +309,11 @@ {{template "shared/combolist" dict "Name" "allowed_channels" "Title" (ctx.Locale.Tr "repo.licenses.channels") "Items" $.ChannelItems "SelectedValues" "" "EmptyText" (ctx.Locale.Tr "repo.licenses.all_channels") "Icon" "octicon-tag"}}

{{ctx.Locale.Tr "repo.licenses.channels_help"}}

+
+ + +

{{ctx.Locale.Tr "repo.licenses.domain_restriction_package_help"}}

+
+
+ + +
+
+ + +
+
+ + +

{{ctx.Locale.Tr "repo.licenses.domain_restriction_help"}}

+
+ {{if .IsSiteAdmin}} +
+ + +

{{ctx.Locale.Tr "repo.licenses.custom_key_help"}}

+
+ {{end}} + {{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.licenses.generate_key"))}} + +
+ +{{end}} + {{/* ── Delete Package Confirmation Modal ── */}} +
+ + +

{{ctx.Locale.Tr "repo.licenses.domain_restriction_package_help"}}

+