feat(t226): add Go ERP session login

This commit is contained in:
QiuSW
2026-07-29 09:51:41 +08:00
parent c2f340d067
commit a5a61c05d0
23 changed files with 1633 additions and 33 deletions
+69
View File
@@ -21,6 +21,9 @@ const (
ReadinessTTLEnvironment = "CMROUBAO_READINESS_TTL"
ERPConnectorURLEnvironment = "CMROUBAO_ERP_CONNECTOR_URL"
ERPConnectorAPIKeyEnvironment = "CMROUBAO_ERP_CONNECTOR_API_KEY"
ShunyunbaoURLEnvironment = "CMROUBAO_SHUNYUNBAO_URL"
ShunyunbaoUsernameEnvironment = "CMROUBAO_SHUNYUNBAO_USERNAME"
ShunyunbaoPasswordEnvironment = "CMROUBAO_SHUNYUNBAO_PASSWORD"
defaultHTTPAddress = "127.0.0.1:8080"
defaultDatabasePath = "var/cmroubao.db"
@@ -29,6 +32,7 @@ const (
defaultRunningLease = 30 * time.Minute
defaultReadinessTTL = 2 * time.Minute
defaultERPConnectorURL = "http://127.0.0.1:8091"
defaultShunyunbaoURL = "https://www.shunyunbaoerp.com"
)
type LookupEnvironment func(string) (string, bool)
@@ -51,6 +55,10 @@ type Config struct {
ERPConnectorURL string
ERPConnectorAPIKey string
ERPConnectorTimeout time.Duration
ShunyunbaoURL string
ShunyunbaoUsername string
ShunyunbaoPassword string
ShunyunbaoTimeout time.Duration
}
func Load(lookup LookupEnvironment) (Config, error) {
@@ -165,6 +173,37 @@ func Load(lookup LookupEnvironment) (Config, error) {
)
}
}
shunyunbaoURL, err := environmentValue(
lookup,
ShunyunbaoURLEnvironment,
defaultShunyunbaoURL,
)
if err != nil {
return Config{}, err
}
if err := validateHTTPSOrigin(shunyunbaoURL, ShunyunbaoURLEnvironment); err != nil {
return Config{}, err
}
shunyunbaoUsername, usernameSet, err := optionalEnvironmentValue(
lookup,
ShunyunbaoUsernameEnvironment,
)
if err != nil {
return Config{}, err
}
shunyunbaoPassword, passwordSet, err := optionalSecretEnvironmentValue(
lookup,
ShunyunbaoPasswordEnvironment,
)
if err != nil {
return Config{}, err
}
if usernameSet != passwordSet {
return Config{}, errors.New(
ShunyunbaoUsernameEnvironment + " and " +
ShunyunbaoPasswordEnvironment + " must be set together",
)
}
return Config{
HTTPAddress: httpAddress,
@@ -184,6 +223,10 @@ func Load(lookup LookupEnvironment) (Config, error) {
ERPConnectorURL: strings.TrimRight(erpConnectorURL, "/"),
ERPConnectorAPIKey: erpConnectorAPIKey,
ERPConnectorTimeout: 90 * time.Second,
ShunyunbaoURL: strings.TrimRight(shunyunbaoURL, "/"),
ShunyunbaoUsername: shunyunbaoUsername,
ShunyunbaoPassword: shunyunbaoPassword,
ShunyunbaoTimeout: 30 * time.Second,
}, nil
}
@@ -214,6 +257,18 @@ func validateLoopbackURL(value string) error {
return nil
}
func validateHTTPSOrigin(value, environment string) error {
parsed, err := url.Parse(value)
if err != nil || parsed.Scheme != "https" || parsed.Host == "" ||
parsed.User != nil || parsed.RawQuery != "" || parsed.Fragment != "" ||
(parsed.Path != "" && parsed.Path != "/") {
return errors.New(
environment + " must be an https origin without credentials or path",
)
}
return nil
}
func durationEnvironment(
lookup LookupEnvironment,
name string,
@@ -261,6 +316,20 @@ func optionalEnvironmentValue(
return value, true, nil
}
func optionalSecretEnvironmentValue(
lookup LookupEnvironment,
name string,
) (string, bool, error) {
value, exists := lookup(name)
if !exists {
return "", false, nil
}
if value == "" || strings.ContainsRune(value, '\x00') {
return "", false, errors.New(name + " must not be blank")
}
return value, true, nil
}
func isLoopbackAddress(address string) bool {
host, _, err := net.SplitHostPort(address)
if err != nil {