package authentik import ( "fmt" "strings" "github.com/ultisuite/ulti-backend/internal/config" ) const suiteGroup = "Ulti Suite" // AppSpec describes one Authentik OAuth application to provision when enabled. type AppSpec struct { Key string Slug string ProviderName string DisplayName string ClientID func(*config.Config) string ClientSecret func(*config.Config) string LaunchURL func(*config.Config) string RedirectURIs func(*config.Config) []string Enabled func(*config.Config) bool OfflineAccess bool } func baseURL(cfg *config.Config) string { host := strings.TrimSpace(cfg.Domain) if host == "" { host = "localhost" } scheme := "http" if cfg.AuthentikPublicHTTPS { scheme = "https" } return fmt.Sprintf("%s://%s", scheme, host) } func Catalog(cfg *config.Config) []AppSpec { return []AppSpec{ { Key: "ultimail", Slug: "ulti", ProviderName: "ulti-backend-provider", DisplayName: "Ultimail", ClientID: func(c *config.Config) string { return c.OIDCClientID }, ClientSecret: func(c *config.Config) string { return c.OIDCClientSecret }, LaunchURL: func(c *config.Config) string { return c.MailAppURL + "/" }, RedirectURIs: ultimailRedirectURIs, Enabled: func(c *config.Config) bool { return c.OIDCClientID != "" && c.OIDCClientSecret != "" }, OfflineAccess: true, }, { Key: "nextcloud", Slug: "nextcloud", ProviderName: "ulti-nextcloud-provider", DisplayName: "Nextcloud", ClientID: func(c *config.Config) string { return c.NCOIDCClientID }, ClientSecret: func(c *config.Config) string { return c.NCOIDCClientSecret }, LaunchURL: func(c *config.Config) string { return baseURL(c) + "/cloud/" }, RedirectURIs: nextcloudRedirectURIs, Enabled: func(c *config.Config) bool { return c.NextcloudEnabled }, }, { Key: "onlyoffice", Slug: "onlyoffice", ProviderName: "ulti-onlyoffice-provider", DisplayName: "OnlyOffice", ClientID: func(c *config.Config) string { return c.OnlyOfficeOIDCClientID }, ClientSecret: func(c *config.Config) string { return c.OnlyOfficeOIDCClientSecret }, LaunchURL: func(c *config.Config) string { return c.OnlyOfficePublicURL }, RedirectURIs: onlyofficeRedirectURIs, Enabled: func(c *config.Config) bool { return c.OnlyOfficeEnabled }, }, { Key: "immich", Slug: "immich", ProviderName: "ulti-immich-provider", DisplayName: "Ultiphotos", ClientID: func(c *config.Config) string { return c.ImmichOIDCClientID }, ClientSecret: func(c *config.Config) string { return c.ImmichOIDCClientSecret }, LaunchURL: func(c *config.Config) string { return baseURL(c) + "/photos/" }, RedirectURIs: immichRedirectURIs, Enabled: func(c *config.Config) bool { return c.ImmichEnabled }, }, { Key: "ultidrive", Slug: "ultidrive", ProviderName: "ulti-drive-provider", DisplayName: "UltiDrive", ClientID: func(c *config.Config) string { return c.DriveOIDCClientID }, ClientSecret: func(c *config.Config) string { return c.DriveOIDCClientSecret }, LaunchURL: func(c *config.Config) string { return baseURL(c) + "/drive/" }, RedirectURIs: driveRedirectURIs, Enabled: func(c *config.Config) bool { return c.NextcloudEnabled && c.DriveOIDCClientID != "" }, }, } } func ultimailRedirectURIs(cfg *config.Config) []string { base := baseURL(cfg) mail := strings.TrimRight(cfg.MailAppURL, "/") drive := strings.TrimRight(base+"/drive", "/") return uniqueURIs( mail+"/api/auth/callback", "http://localhost:3000/api/auth/callback", "http://127.0.0.1:3000/api/auth/callback", drive+"/api/auth/callback", "http://localhost:3001/api/auth/callback", "http://127.0.0.1:3001/api/auth/callback", base+"/api/auth/callback", ) } func nextcloudRedirectURIs(cfg *config.Config) []string { base := baseURL(cfg) return uniqueURIs( base+"/cloud/apps/user_oidc/code", "http://localhost/cloud/apps/user_oidc/code", "http://127.0.0.1/cloud/apps/user_oidc/code", ) } func onlyofficeRedirectURIs(cfg *config.Config) []string { base := baseURL(cfg) office := strings.TrimRight(cfg.OnlyOfficePublicURL, "/") return uniqueURIs( office+"/", office+"/oauth2/callback", base+"/office/", base+"/office/oauth2/callback", "http://localhost/office/", ) } func immichRedirectURIs(cfg *config.Config) []string { base := baseURL(cfg) return uniqueURIs( base+"/photos/auth/login", base+"/photos/user-settings", "http://localhost/photos/auth/login", ) } func driveRedirectURIs(cfg *config.Config) []string { base := baseURL(cfg) drive := strings.TrimRight(base+"/drive", "/") return uniqueURIs( drive+"/api/auth/callback", "http://localhost:3001/api/auth/callback", "http://127.0.0.1:3001/api/auth/callback", ) } func uniqueURIs(uris ...string) []string { seen := map[string]struct{}{} var out []string for _, u := range uris { u = strings.TrimSpace(u) if u == "" { continue } if _, ok := seen[u]; ok { continue } seen[u] = struct{}{} out = append(out, u) } return out }