mirror of
https://codeberg.org/forgejo/forgejo
synced 2024-11-28 04:36:11 +01:00
Compare commits
1 commit
16d06705b3
...
735c2c8ada
Author | SHA1 | Date | |
---|---|---|---|
735c2c8ada |
109
build/generate-disposable-email.go
Normal file
109
build/generate-disposable-email.go
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
// Copyright 2024 James Hatfield
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
//go:build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const disposableEmailListURL string = "https://raw.githubusercontent.com/disposable-email-domains/disposable-email-domains/%s/disposable_email_blocklist.conf"
|
||||||
|
|
||||||
|
var (
|
||||||
|
gitRef *string = flag.String("r", "master", "Git reference of the domain list version")
|
||||||
|
outPat *string = flag.String("o", "modules/setting/disposable_email_domain_data.go", "Output path")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// generate the source code (array of domains)
|
||||||
|
res, err := generate()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Generation Error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write result to a file
|
||||||
|
err = os.WriteFile(*outPat, res, 0o644)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("File Write Error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generate() ([]byte, error) {
|
||||||
|
var err error
|
||||||
|
var url string = fmt.Sprintf(disposableEmailListURL, *gitRef)
|
||||||
|
|
||||||
|
// download the domain list
|
||||||
|
res, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// go through all entries (1 domain per line)
|
||||||
|
scanner := bufio.NewScanner(bytes.NewReader(body))
|
||||||
|
|
||||||
|
var arrDomains []string
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
|
||||||
|
arrDomains = append(arrDomains, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the string in a readable way
|
||||||
|
var sb strings.Builder
|
||||||
|
|
||||||
|
_, err = sb.WriteString("[]string{\n")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range arrDomains {
|
||||||
|
_, err = sb.WriteString(fmt.Sprintf("\t%q,\n", item))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = sb.WriteString("}")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert the values into file
|
||||||
|
final := fmt.Sprintf(hdr, url, sb.String())
|
||||||
|
|
||||||
|
return format.Source([]byte(final))
|
||||||
|
}
|
||||||
|
|
||||||
|
const hdr = `
|
||||||
|
// Copyright 2024 James Hatfield
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// Code generated by build/generate-disposable-email.go. DO NOT EDIT
|
||||||
|
// Sourced from %s
|
||||||
|
package setting
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
var DisposableEmailDomains = sync.OnceValue(func() []string {
|
||||||
|
return %s
|
||||||
|
})
|
||||||
|
`
|
3811
modules/setting/disposable_email_domain_data.go
Normal file
3811
modules/setting/disposable_email_domain_data.go
Normal file
File diff suppressed because it is too large
Load diff
|
@ -5,6 +5,7 @@ package setting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ var Service = struct {
|
||||||
RegisterManualConfirm bool
|
RegisterManualConfirm bool
|
||||||
EmailDomainAllowList []glob.Glob
|
EmailDomainAllowList []glob.Glob
|
||||||
EmailDomainBlockList []glob.Glob
|
EmailDomainBlockList []glob.Glob
|
||||||
|
EmailDomainBlockDisposable bool
|
||||||
DisableRegistration bool
|
DisableRegistration bool
|
||||||
AllowOnlyInternalRegistration bool
|
AllowOnlyInternalRegistration bool
|
||||||
AllowOnlyExternalRegistration bool
|
AllowOnlyExternalRegistration bool
|
||||||
|
@ -156,6 +158,22 @@ func loadServiceFrom(rootCfg ConfigProvider) {
|
||||||
}
|
}
|
||||||
Service.EmailDomainAllowList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_WHITELIST", "EMAIL_DOMAIN_ALLOWLIST")
|
Service.EmailDomainAllowList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_WHITELIST", "EMAIL_DOMAIN_ALLOWLIST")
|
||||||
Service.EmailDomainBlockList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_BLOCKLIST")
|
Service.EmailDomainBlockList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_BLOCKLIST")
|
||||||
|
Service.EmailDomainBlockDisposable = sec.Key("EMAIL_DOMAIN_BLOCK_DISPOSABLE").MustBool(false)
|
||||||
|
if Service.EmailDomainBlockDisposable {
|
||||||
|
toAdd := make([]glob.Glob, 0, len(DisposableEmailDomains()))
|
||||||
|
for _, domain := range DisposableEmailDomains() {
|
||||||
|
domain = strings.ToLower(domain)
|
||||||
|
// Only add domains that aren't blocked yet.
|
||||||
|
if !slices.ContainsFunc(Service.EmailDomainBlockList, func(g glob.Glob) bool { return g.Match(domain) }) {
|
||||||
|
if g, err := glob.Compile(domain); err != nil {
|
||||||
|
log.Error("Error in disposable domain %s: %v", domain, err)
|
||||||
|
} else {
|
||||||
|
toAdd = append(toAdd, g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Service.EmailDomainBlockList = append(Service.EmailDomainBlockList, toAdd...)
|
||||||
|
}
|
||||||
Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration))
|
Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration))
|
||||||
Service.ShowMilestonesDashboardPage = sec.Key("SHOW_MILESTONES_DASHBOARD_PAGE").MustBool(true)
|
Service.ShowMilestonesDashboardPage = sec.Key("SHOW_MILESTONES_DASHBOARD_PAGE").MustBool(true)
|
||||||
Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
|
Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package setting
|
package setting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
@ -13,6 +14,15 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func match(globs []glob.Glob, s string) bool {
|
||||||
|
for _, g := range globs {
|
||||||
|
if g.Match(s) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoadServices(t *testing.T) {
|
func TestLoadServices(t *testing.T) {
|
||||||
oldService := Service
|
oldService := Service
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -28,15 +38,6 @@ EMAIL_DOMAIN_BLOCKLIST = d3, *.b
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
loadServiceFrom(cfg)
|
loadServiceFrom(cfg)
|
||||||
|
|
||||||
match := func(globs []glob.Glob, s string) bool {
|
|
||||||
for _, g := range globs {
|
|
||||||
if g.Match(s) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.True(t, match(Service.EmailDomainAllowList, "d1"))
|
assert.True(t, match(Service.EmailDomainAllowList, "d1"))
|
||||||
assert.True(t, match(Service.EmailDomainAllowList, "foo.w"))
|
assert.True(t, match(Service.EmailDomainAllowList, "foo.w"))
|
||||||
assert.True(t, match(Service.EmailDomainAllowList, "d2"))
|
assert.True(t, match(Service.EmailDomainAllowList, "d2"))
|
||||||
|
@ -48,6 +49,97 @@ EMAIL_DOMAIN_BLOCKLIST = d3, *.b
|
||||||
assert.False(t, match(Service.EmailDomainBlockList, "d1"))
|
assert.False(t, match(Service.EmailDomainBlockList, "d1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadServiceBlockDisposable(t *testing.T) {
|
||||||
|
oldService := Service
|
||||||
|
defer func() {
|
||||||
|
Service = oldService
|
||||||
|
}()
|
||||||
|
|
||||||
|
cfg, err := NewConfigProviderFromData(`
|
||||||
|
[service]
|
||||||
|
EMAIL_DOMAIN_BLOCK_DISPOSABLE = true
|
||||||
|
`)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
loadServiceFrom(cfg)
|
||||||
|
|
||||||
|
for _, domain := range DisposableEmailDomains() {
|
||||||
|
require.True(t, match(Service.EmailDomainBlockList, domain))
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Len(t, Service.EmailDomainBlockList, len(DisposableEmailDomains()))
|
||||||
|
|
||||||
|
knownGood := [...]string{
|
||||||
|
"aol.com",
|
||||||
|
"gmx.com",
|
||||||
|
"mail.com",
|
||||||
|
"zoho.com",
|
||||||
|
"proton.me",
|
||||||
|
"gmail.com",
|
||||||
|
"yahoo.com",
|
||||||
|
"icloud.com",
|
||||||
|
"outlook.com",
|
||||||
|
"protonmail.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, domain := range knownGood {
|
||||||
|
require.False(t, match(Service.EmailDomainBlockList, domain))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadServiceBlockDisposableWithExistingGlobs(t *testing.T) {
|
||||||
|
oldService := Service
|
||||||
|
defer func() {
|
||||||
|
Service = oldService
|
||||||
|
}()
|
||||||
|
|
||||||
|
cfg, err := NewConfigProviderFromData(`
|
||||||
|
[service]
|
||||||
|
EMAIL_DOMAIN_BLOCKLIST = *.ru,*.org
|
||||||
|
EMAIL_DOMAIN_BLOCK_DISPOSABLE = true
|
||||||
|
`)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
loadServiceFrom(cfg)
|
||||||
|
|
||||||
|
for _, domain := range DisposableEmailDomains() {
|
||||||
|
require.True(t, match(Service.EmailDomainBlockList, domain))
|
||||||
|
}
|
||||||
|
|
||||||
|
redundant := 0
|
||||||
|
for _, val := range DisposableEmailDomains() {
|
||||||
|
if strings.HasSuffix(val, ".ru") || strings.HasSuffix(val, ".org") {
|
||||||
|
redundant++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := len(DisposableEmailDomains()) - redundant + 2
|
||||||
|
require.Len(t, Service.EmailDomainBlockList, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadServiceBlockDisposableWithComplementGlobs(t *testing.T) {
|
||||||
|
oldService := Service
|
||||||
|
defer func() {
|
||||||
|
Service = oldService
|
||||||
|
}()
|
||||||
|
|
||||||
|
cfg, err := NewConfigProviderFromData(`
|
||||||
|
[service]
|
||||||
|
EMAIL_DOMAIN_BLOCKLIST = *.random
|
||||||
|
EMAIL_DOMAIN_BLOCK_DISPOSABLE = true
|
||||||
|
`)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
loadServiceFrom(cfg)
|
||||||
|
|
||||||
|
for _, domain := range DisposableEmailDomains() {
|
||||||
|
require.True(t, match(Service.EmailDomainBlockList, domain))
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := len(DisposableEmailDomains()) + 1
|
||||||
|
require.Len(t, Service.EmailDomainBlockList, expected)
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoadServiceVisibilityModes(t *testing.T) {
|
func TestLoadServiceVisibilityModes(t *testing.T) {
|
||||||
oldService := Service
|
oldService := Service
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
Loading…
Reference in a new issue