mirror of
https://github.com/pocket-id/pocket-id.git
synced 2025-12-17 09:13:28 +03:00
feat: add custom base url (#858)
Co-authored-by: Stephan Höhn <me@steph.ovh> Co-authored-by: Kyle Mendell <ksm@ofkm.us>
This commit is contained in:
@@ -27,6 +27,7 @@ const (
|
|||||||
DbProviderPostgres DbProvider = "postgres"
|
DbProviderPostgres DbProvider = "postgres"
|
||||||
MaxMindGeoLiteCityUrl string = "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=%s&suffix=tar.gz"
|
MaxMindGeoLiteCityUrl string = "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=%s&suffix=tar.gz"
|
||||||
defaultSqliteConnString string = "data/pocket-id.db"
|
defaultSqliteConnString string = "data/pocket-id.db"
|
||||||
|
AppUrl string = "http://localhost:1411"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EnvConfigSchema struct {
|
type EnvConfigSchema struct {
|
||||||
@@ -53,6 +54,7 @@ type EnvConfigSchema struct {
|
|||||||
TrustProxy bool `env:"TRUST_PROXY"`
|
TrustProxy bool `env:"TRUST_PROXY"`
|
||||||
AnalyticsDisabled bool `env:"ANALYTICS_DISABLED"`
|
AnalyticsDisabled bool `env:"ANALYTICS_DISABLED"`
|
||||||
AllowDowngrade bool `env:"ALLOW_DOWNGRADE"`
|
AllowDowngrade bool `env:"ALLOW_DOWNGRADE"`
|
||||||
|
InternalAppURL string `env:"INTERNAL_APP_URL"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var EnvConfig = defaultConfig()
|
var EnvConfig = defaultConfig()
|
||||||
@@ -74,7 +76,7 @@ func defaultConfig() EnvConfigSchema {
|
|||||||
KeysPath: "data/keys",
|
KeysPath: "data/keys",
|
||||||
KeysStorage: "", // "database" or "file"
|
KeysStorage: "", // "database" or "file"
|
||||||
EncryptionKey: nil,
|
EncryptionKey: nil,
|
||||||
AppURL: "http://localhost:1411",
|
AppURL: AppUrl,
|
||||||
Port: "1411",
|
Port: "1411",
|
||||||
Host: "0.0.0.0",
|
Host: "0.0.0.0",
|
||||||
UnixSocket: "",
|
UnixSocket: "",
|
||||||
@@ -89,6 +91,7 @@ func defaultConfig() EnvConfigSchema {
|
|||||||
TrustProxy: false,
|
TrustProxy: false,
|
||||||
AnalyticsDisabled: false,
|
AnalyticsDisabled: false,
|
||||||
AllowDowngrade: false,
|
AllowDowngrade: false,
|
||||||
|
InternalAppURL: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +136,19 @@ func parseEnvConfig() error {
|
|||||||
return errors.New("APP_URL must not contain a path")
|
return errors.New("APP_URL must not contain a path")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Derive INTERNAL_APP_URL from APP_URL if not set; validate only when provided
|
||||||
|
if EnvConfig.InternalAppURL == "" {
|
||||||
|
EnvConfig.InternalAppURL = EnvConfig.AppURL
|
||||||
|
} else {
|
||||||
|
parsedInternalAppUrl, err := url.Parse(EnvConfig.InternalAppURL)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("INTERNAL_APP_URL is not a valid URL")
|
||||||
|
}
|
||||||
|
if parsedInternalAppUrl.Path != "" {
|
||||||
|
return errors.New("INTERNAL_APP_URL must not contain a path")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch EnvConfig.KeysStorage {
|
switch EnvConfig.KeysStorage {
|
||||||
// KeysStorage defaults to "file" if empty
|
// KeysStorage defaults to "file" if empty
|
||||||
case "":
|
case "":
|
||||||
|
|||||||
@@ -91,6 +91,28 @@ func TestParseEnvConfig(t *testing.T) {
|
|||||||
assert.ErrorContains(t, err, "APP_URL must not contain a path")
|
assert.ErrorContains(t, err, "APP_URL must not contain a path")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("should fail with invalid INTERNAL_APP_URL", func(t *testing.T) {
|
||||||
|
EnvConfig = defaultConfig()
|
||||||
|
t.Setenv("DB_PROVIDER", "sqlite")
|
||||||
|
t.Setenv("DB_CONNECTION_STRING", "file:test.db")
|
||||||
|
t.Setenv("INTERNAL_APP_URL", "€://not-a-valid-url")
|
||||||
|
|
||||||
|
err := parseEnvConfig()
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.ErrorContains(t, err, "INTERNAL_APP_URL is not a valid URL")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should fail when INTERNAL_APP_URL contains path", func(t *testing.T) {
|
||||||
|
EnvConfig = defaultConfig()
|
||||||
|
t.Setenv("DB_PROVIDER", "sqlite")
|
||||||
|
t.Setenv("DB_CONNECTION_STRING", "file:test.db")
|
||||||
|
t.Setenv("INTERNAL_APP_URL", "http://localhost:3000/path")
|
||||||
|
|
||||||
|
err := parseEnvConfig()
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.ErrorContains(t, err, "INTERNAL_APP_URL must not contain a path")
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("should default KEYS_STORAGE to 'file' when empty", func(t *testing.T) {
|
t.Run("should default KEYS_STORAGE to 'file' when empty", func(t *testing.T) {
|
||||||
EnvConfig = defaultConfig()
|
EnvConfig = defaultConfig()
|
||||||
t.Setenv("DB_PROVIDER", "sqlite")
|
t.Setenv("DB_PROVIDER", "sqlite")
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ func (wkc *WellKnownController) openIDConfigurationHandler(c *gin.Context) {
|
|||||||
|
|
||||||
func (wkc *WellKnownController) computeOIDCConfiguration() ([]byte, error) {
|
func (wkc *WellKnownController) computeOIDCConfiguration() ([]byte, error) {
|
||||||
appUrl := common.EnvConfig.AppURL
|
appUrl := common.EnvConfig.AppURL
|
||||||
|
|
||||||
|
internalAppUrl := common.EnvConfig.InternalAppURL
|
||||||
|
|
||||||
alg, err := wkc.jwtService.GetKeyAlg()
|
alg, err := wkc.jwtService.GetKeyAlg()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get key algorithm: %w", err)
|
return nil, fmt.Errorf("failed to get key algorithm: %w", err)
|
||||||
@@ -74,12 +77,12 @@ func (wkc *WellKnownController) computeOIDCConfiguration() ([]byte, error) {
|
|||||||
config := map[string]any{
|
config := map[string]any{
|
||||||
"issuer": appUrl,
|
"issuer": appUrl,
|
||||||
"authorization_endpoint": appUrl + "/authorize",
|
"authorization_endpoint": appUrl + "/authorize",
|
||||||
"token_endpoint": appUrl + "/api/oidc/token",
|
"token_endpoint": internalAppUrl + "/api/oidc/token",
|
||||||
"userinfo_endpoint": appUrl + "/api/oidc/userinfo",
|
"userinfo_endpoint": internalAppUrl + "/api/oidc/userinfo",
|
||||||
"end_session_endpoint": appUrl + "/api/oidc/end-session",
|
"end_session_endpoint": appUrl + "/api/oidc/end-session",
|
||||||
"introspection_endpoint": appUrl + "/api/oidc/introspect",
|
"introspection_endpoint": internalAppUrl + "/api/oidc/introspect",
|
||||||
"device_authorization_endpoint": appUrl + "/api/oidc/device/authorize",
|
"device_authorization_endpoint": appUrl + "/api/oidc/device/authorize",
|
||||||
"jwks_uri": appUrl + "/.well-known/jwks.json",
|
"jwks_uri": internalAppUrl + "/.well-known/jwks.json",
|
||||||
"grant_types_supported": []string{service.GrantTypeAuthorizationCode, service.GrantTypeRefreshToken, service.GrantTypeDeviceCode},
|
"grant_types_supported": []string{service.GrantTypeAuthorizationCode, service.GrantTypeRefreshToken, service.GrantTypeDeviceCode},
|
||||||
"scopes_supported": []string{"openid", "profile", "email", "groups"},
|
"scopes_supported": []string{"openid", "profile", "email", "groups"},
|
||||||
"claims_supported": []string{"sub", "given_name", "family_name", "name", "email", "email_verified", "preferred_username", "picture", "groups"},
|
"claims_supported": []string{"sub", "given_name", "family_name", "name", "email", "email_verified", "preferred_username", "picture", "groups"},
|
||||||
|
|||||||
Reference in New Issue
Block a user