mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-14 04:16:06 +00:00
fix: allow self-hosted Bitrix24 domains for portal registration
Split bitrixDomainRegex into bitrixCloudDomainRegex (cloud SaaS domains)
and selfHostedDomainRegex (custom FQDNs). Users can now register portals
with self-hosted Bitrix24 instances like bx.mycompany.com instead of
being restricted to *.bitrix24.{com,eu,...} domains.
This commit is contained in:
1 parent
45f789563d
commit
ee26bc90bf
2 files changed
+59
-7
No files matched your search
@@ -71,7 +71,11 @@ type bitrixPortalView struct {
|
||||
var (
|
||||
// Bitrix24 cloud portal hosts. Matches *.bitrix24.{com,eu,ru,de,fr,jp,in,kz,ua,by}
|
||||
// plus self-hosted *.bitrix.info. Subdomain regex matches DNS label rules.
|
||||
bitrixDomainRegex = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.(bitrix24\.(com|eu|ru|de|fr|jp|in|kz|ua|by)|bitrix\.info)$`)
|
||||
bitrixCloudDomainRegex = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.(bitrix24\.(com|eu|ru|de|fr|jp|in|kz|ua|by)|bitrix\.info)$`)
|
||||
|
||||
// Valid hostname regex for self-hosted Bitrix24 instances (custom domains).
|
||||
// Accepts any valid FQDN or hostname with optional port (e.g. bx.example.com, portal.internal:8443).
|
||||
selfHostedDomainRegex = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*(\:\d+)?$`)
|
||||
|
||||
// Portal name: lowercase slug used in install state token + channel config
|
||||
// reference. Underscore allowed for legacy CLI-created portals.
|
||||
@@ -142,8 +146,8 @@ func (m *BitrixPortalsMethods) handleCreate(ctx context.Context, client *gateway
|
||||
client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInvalidRequest, i18n.T(locale, i18n.MsgInvalidRequest, "name: lowercase letters, digits, hyphen, underscore (2-64 chars)")))
|
||||
return
|
||||
}
|
||||
if !bitrixDomainRegex.MatchString(domain) {
|
||||
client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInvalidRequest, i18n.T(locale, i18n.MsgInvalidRequest, "domain: must be *.bitrix24.{com,eu,ru,…} or *.bitrix.info")))
|
||||
if !bitrixCloudDomainRegex.MatchString(domain) && !selfHostedDomainRegex.MatchString(domain) {
|
||||
client.SendResponse(protocol.NewErrorResponse(req.ID, protocol.ErrInvalidRequest, i18n.T(locale, i18n.MsgInvalidRequest, "domain: must be a valid hostname (e.g. *.bitrix24.com, *.bitrix.info, or your self-hosted domain)")))
|
||||
return
|
||||
}
|
||||
if clientID == "" || clientSecret == "" {
|
||||
|
||||
@@ -369,7 +369,7 @@ func TestBitrixPortals_Create_InvalidDomain(t *testing.T) {
|
||||
client, ch := gateway.NewCapturingTestClient(permissions.RoleAdmin, tid, "u", 4)
|
||||
m.handleCreate(store.WithTenantID(context.Background(), tid), client, buildBitrixReq(t, protocol.MethodBitrixPortalsCreate, map[string]string{
|
||||
"name": "p",
|
||||
"domain": "not-a-bitrix-domain.com",
|
||||
"domain": "-invalid.com",
|
||||
"client_id": "x",
|
||||
"client_secret": "y",
|
||||
}))
|
||||
@@ -380,6 +380,29 @@ func TestBitrixPortals_Create_InvalidDomain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBitrixPortals_Create_SelfHostedDomain(t *testing.T) {
|
||||
tid := uuid.MustParse("22222222-2222-2222-2222-222222222222")
|
||||
pStore := newStubBitrixPortalStore()
|
||||
m := NewBitrixPortalsMethods(pStore, newStubChannelInstanceStore(), gatewayURLFn("https://goclaw.tamgiac.com"))
|
||||
|
||||
client, ch := gateway.NewCapturingTestClient(permissions.RoleAdmin, tid, "admin", 4)
|
||||
m.handleCreate(store.WithTenantID(context.Background(), tid), client, buildBitrixReq(t, protocol.MethodBitrixPortalsCreate, map[string]string{
|
||||
"name": "myportal",
|
||||
"domain": "bx.mycompany.com",
|
||||
"client_id": "local.abc",
|
||||
"client_secret": "secret123",
|
||||
}))
|
||||
|
||||
resp := readResponse(t, ch)
|
||||
if resp.Error != nil {
|
||||
t.Fatalf("create with self-hosted domain failed: %+v", resp.Error)
|
||||
}
|
||||
result := resp.Payload.(map[string]any)
|
||||
if result["domain"] != "bx.mycompany.com" {
|
||||
t.Errorf("domain = %q, want bx.mycompany.com", result["domain"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestBitrixPortals_Create_InvalidName(t *testing.T) {
|
||||
tid := uuid.New()
|
||||
m := NewBitrixPortalsMethods(newStubBitrixPortalStore(), newStubChannelInstanceStore(), gatewayURLFn("https://gw.example.com"))
|
||||
@@ -543,19 +566,44 @@ func TestBitrixDomainRegex(t *testing.T) {
|
||||
}
|
||||
bad := []string{
|
||||
"tamgiac.bitrix24",
|
||||
"tamgiac.example.com",
|
||||
"tamgiac.bitrix24.xx",
|
||||
"-bad.bitrix24.com",
|
||||
"UPPER.bitrix24.com", // we lowercase before match
|
||||
"a.b.bitrix24.com", // multi-level subdomain not allowed
|
||||
}
|
||||
for _, d := range good {
|
||||
if !bitrixDomainRegex.MatchString(d) {
|
||||
if !bitrixCloudDomainRegex.MatchString(d) {
|
||||
t.Errorf("should accept %q", d)
|
||||
}
|
||||
}
|
||||
for _, d := range bad {
|
||||
if bitrixDomainRegex.MatchString(d) {
|
||||
if bitrixCloudDomainRegex.MatchString(d) {
|
||||
t.Errorf("should reject %q", d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelfHostedDomainRegex(t *testing.T) {
|
||||
good := []string{
|
||||
"bx.example.com",
|
||||
"portal.internal",
|
||||
"bitrix.mycompany.co.uk",
|
||||
"portal.example.com:8443",
|
||||
"bx.corp",
|
||||
}
|
||||
bad := []string{
|
||||
"-bad.example.com",
|
||||
"UPPER.example.com", // we lowercase before match
|
||||
"",
|
||||
"not a domain",
|
||||
}
|
||||
for _, d := range good {
|
||||
if !selfHostedDomainRegex.MatchString(d) {
|
||||
t.Errorf("should accept %q", d)
|
||||
}
|
||||
}
|
||||
for _, d := range bad {
|
||||
if selfHostedDomainRegex.MatchString(d) {
|
||||
t.Errorf("should reject %q", d)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user