bab29a83fa
Sweep all .go imports + go.mod, plus module-path refs in .golangci.yml, Dockerfile, swagger templates, locale example, and repo/wiki URLs (MokoGitea-Fork -> MokoGIT). Part of the MokoGIT rebrand. Claude-Session: https://claude.ai/code/session_01Bqe7fAuHQeiLueYfeHFrHw
135 lines
4.0 KiB
Go
135 lines
4.0 KiB
Go
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package git
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"code.mokoconsulting.tech/MokoConsulting/MokoGIT/models/db"
|
|
"code.mokoconsulting.tech/MokoConsulting/MokoGIT/modules/glob"
|
|
"code.mokoconsulting.tech/MokoConsulting/MokoGIT/modules/log"
|
|
"code.mokoconsulting.tech/MokoConsulting/MokoGIT/modules/timeutil"
|
|
|
|
"xorm.io/builder"
|
|
)
|
|
|
|
// OrgEmailDomainPolicy restricts which email domains an organization's members may
|
|
// have. When configured, a user can only be added to the org if their primary email
|
|
// matches one of the allowed domain globs. At most one row per org. See issue #727.
|
|
type OrgEmailDomainPolicy struct {
|
|
ID int64 `xorm:"pk autoincr"`
|
|
OrgID int64 `xorm:"UNIQUE NOT NULL"`
|
|
AllowedDomains string `xorm:"TEXT"`
|
|
CreatedUnix timeutil.TimeStamp `xorm:"created"`
|
|
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
|
|
}
|
|
|
|
func init() {
|
|
db.RegisterModel(new(OrgEmailDomainPolicy))
|
|
}
|
|
|
|
// ErrEmailDomainNotAllowed is returned when a user's email domain is not permitted
|
|
// by the organization's email domain policy.
|
|
type ErrEmailDomainNotAllowed struct {
|
|
Email string
|
|
OrgID int64
|
|
}
|
|
|
|
func (e ErrEmailDomainNotAllowed) Error() string {
|
|
return fmt.Sprintf("email %q is not in an allowed domain for organization %d", e.Email, e.OrgID)
|
|
}
|
|
|
|
// IsErrEmailDomainNotAllowed reports whether err is an ErrEmailDomainNotAllowed.
|
|
func IsErrEmailDomainNotAllowed(err error) bool {
|
|
_, ok := err.(ErrEmailDomainNotAllowed)
|
|
return ok
|
|
}
|
|
|
|
func (p *OrgEmailDomainPolicy) domainGlobs() []glob.Glob {
|
|
var out []glob.Glob
|
|
for _, d := range strings.Split(p.AllowedDomains, ";") {
|
|
d = strings.TrimSpace(strings.ToLower(d))
|
|
if d == "" {
|
|
continue
|
|
}
|
|
if g, err := glob.Compile(d); err == nil {
|
|
out = append(out, g)
|
|
} else {
|
|
log.Warn("Invalid org email domain glob %q: %v", d, err)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// EmailAllowed reports whether email's domain satisfies the policy. An empty policy
|
|
// (no configured domains) allows any email.
|
|
func (p *OrgEmailDomainPolicy) EmailAllowed(email string) bool {
|
|
globs := p.domainGlobs()
|
|
if len(globs) == 0 {
|
|
return true
|
|
}
|
|
at := strings.LastIndexByte(email, '@')
|
|
if at < 0 {
|
|
return false
|
|
}
|
|
domain := strings.ToLower(email[at+1:])
|
|
for _, g := range globs {
|
|
if g.Match(domain) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetOrgEmailDomainPolicy returns the org's email domain policy, or nil if none.
|
|
func GetOrgEmailDomainPolicy(ctx context.Context, orgID int64) (*OrgEmailDomainPolicy, error) {
|
|
policy, exist, err := db.Get[OrgEmailDomainPolicy](ctx, builder.Eq{"org_id": orgID})
|
|
if err != nil {
|
|
return nil, err
|
|
} else if !exist {
|
|
return nil, nil //nolint:nilnil
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// OrgEmailDomainAllowed reports whether email is permitted for the org. It returns
|
|
// true when the org has no policy configured.
|
|
func OrgEmailDomainAllowed(ctx context.Context, orgID int64, email string) (bool, error) {
|
|
policy, err := GetOrgEmailDomainPolicy(ctx, orgID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if policy == nil {
|
|
return true, nil
|
|
}
|
|
return policy.EmailAllowed(email), nil
|
|
}
|
|
|
|
// UpsertOrgEmailDomainPolicy creates or updates the single policy row for an org.
|
|
func UpsertOrgEmailDomainPolicy(ctx context.Context, policy *OrgEmailDomainPolicy) error {
|
|
existing, err := GetOrgEmailDomainPolicy(ctx, policy.OrgID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if existing == nil {
|
|
if _, err := db.GetEngine(ctx).Insert(policy); err != nil {
|
|
return fmt.Errorf("Insert OrgEmailDomainPolicy: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
policy.ID = existing.ID
|
|
if _, err := db.GetEngine(ctx).ID(existing.ID).AllCols().Update(policy); err != nil {
|
|
return fmt.Errorf("Update OrgEmailDomainPolicy: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeleteOrgEmailDomainPolicy removes an org's email domain policy.
|
|
func DeleteOrgEmailDomainPolicy(ctx context.Context, orgID int64) error {
|
|
_, err := db.GetEngine(ctx).Where("org_id = ?", orgID).Delete(new(OrgEmailDomainPolicy))
|
|
return err
|
|
}
|