diff --git a/internal/api/subscription.go b/internal/api/subscription.go index 63eeba73..9193f37b 100644 --- a/internal/api/subscription.go +++ b/internal/api/subscription.go @@ -30,9 +30,11 @@ func (h *handler) discoverSubscriptions(w http.ResponseWriter, r *http.Request) } var rssbridgeURL string + var rssbridgeToken string intg, err := h.store.Integration(request.UserID(r)) if err == nil && intg != nil && intg.RSSBridgeEnabled { rssbridgeURL = intg.RSSBridgeURL + rssbridgeToken = intg.RSSBridgeToken } requestBuilder := fetcher.NewRequestBuilder() @@ -50,6 +52,7 @@ func (h *handler) discoverSubscriptions(w http.ResponseWriter, r *http.Request) subscriptions, localizedError := subscription.NewSubscriptionFinder(requestBuilder).FindSubscriptions( subscriptionDiscoveryRequest.URL, rssbridgeURL, + rssbridgeToken, ) if localizedError != nil { diff --git a/internal/database/migrations.go b/internal/database/migrations.go index 4f553e9c..16930a47 100644 --- a/internal/database/migrations.go +++ b/internal/database/migrations.go @@ -1066,4 +1066,11 @@ var migrations = []func(tx *sql.Tx, driver string) error{ _, err = tx.Exec(`ALTER TABLE feeds ADD COLUMN proxy_url text default ''`) return err }, + func(tx *sql.Tx, _ string) (err error) { + sql := ` + ALTER TABLE integrations ADD COLUMN rssbridge_token text default ''; + ` + _, err = tx.Exec(sql) + return + }, } diff --git a/internal/googlereader/handler.go b/internal/googlereader/handler.go index 38279e2c..eabdc780 100644 --- a/internal/googlereader/handler.go +++ b/internal/googlereader/handler.go @@ -418,11 +418,13 @@ func (h *handler) quickAddHandler(w http.ResponseWriter, r *http.Request) { requestBuilder.WithProxyRotator(proxyrotator.ProxyRotatorInstance) var rssBridgeURL string + var rssBridgeToken string if intg, err := h.store.Integration(userID); err == nil && intg != nil && intg.RSSBridgeEnabled { rssBridgeURL = intg.RSSBridgeURL + rssBridgeToken = intg.RSSBridgeToken } - subscriptions, localizedError := mfs.NewSubscriptionFinder(requestBuilder).FindSubscriptions(feedURL, rssBridgeURL) + subscriptions, localizedError := mfs.NewSubscriptionFinder(requestBuilder).FindSubscriptions(feedURL, rssBridgeURL, rssBridgeToken) if localizedError != nil { json.ServerError(w, r, localizedError.Error()) return diff --git a/internal/integration/rssbridge/rssbridge.go b/internal/integration/rssbridge/rssbridge.go index aab4c210..713f05cf 100644 --- a/internal/integration/rssbridge/rssbridge.go +++ b/internal/integration/rssbridge/rssbridge.go @@ -24,13 +24,16 @@ type BridgeMeta struct { Name string `json:"name"` } -func DetectBridges(rssBridgeURL, websiteURL string) ([]*Bridge, error) { +func DetectBridges(rssBridgeURL, rssBridgeToken, websiteURL string) ([]*Bridge, error) { endpointURL, err := url.Parse(rssBridgeURL) if err != nil { return nil, fmt.Errorf("RSS-Bridge: unable to parse bridge URL: %w", err) } values := endpointURL.Query() + if rssBridgeToken != "" { + values.Add("token", rssBridgeToken) + } values.Add("action", "findfeed") values.Add("format", "atom") values.Add("url", websiteURL) @@ -78,6 +81,15 @@ func DetectBridges(rssBridgeURL, websiteURL string) ([]*Bridge, error) { slog.String("url", bridge.URL), ) } + + if rssBridgeToken != "" { + bridge.URL = bridge.URL + "&token=" + rssBridgeToken + + slog.Debug("Appended token to RSS bridge URL", + slog.String("name", bridge.BridgeMeta.Name), + slog.String("url", bridge.URL), + ) + } } return bridgeResponse, nil diff --git a/internal/locale/translations/en_US.json b/internal/locale/translations/en_US.json index 245e2e8c..ee4e1847 100644 --- a/internal/locale/translations/en_US.json +++ b/internal/locale/translations/en_US.json @@ -295,6 +295,7 @@ "form.integration.readwise_api_key": "Readwise Reader Access Token", "form.integration.readwise_api_key_link": "Get your Readwise Access Token", "form.integration.rssbridge_activate": "Check RSS-Bridge when adding subscriptions", + "form.integration.rssbridge_token": "RSS-Bridge authentication token", "form.integration.rssbridge_url": "RSS-Bridge server URL", "form.integration.shaarli_activate": "Save articles to Shaarli", "form.integration.shaarli_api_secret": "Shaarli API Secret", @@ -608,4 +609,4 @@ "time_elapsed.yesterday": "yesterday", "tooltip.keyboard_shortcuts": "Keyboard Shortcut: %s", "tooltip.logged_user": "Logged in as %s" -} \ No newline at end of file +} diff --git a/internal/locale/translations/ru_RU.json b/internal/locale/translations/ru_RU.json index bab4a8de..9176f252 100644 --- a/internal/locale/translations/ru_RU.json +++ b/internal/locale/translations/ru_RU.json @@ -297,6 +297,7 @@ "form.integration.readwise_api_key": "Токен доступа в Readwise", "form.integration.readwise_api_key_link": "Получить токен доступа Readwise", "form.integration.rssbridge_activate": "Check RSS-Bridge when adding subscriptions", + "form.integration.rssbridge_token": "RSS-Bridge authentication token", "form.integration.rssbridge_url": "RSS-Bridge server URL", "form.integration.shaarli_activate": "Сохранить статьи в Shaarli", "form.integration.shaarli_api_secret": "Секретный ключ Shaarli API", @@ -625,4 +626,4 @@ "time_elapsed.yesterday": "вчера", "tooltip.keyboard_shortcuts": "Сочетания клавиш: %s", "tooltip.logged_user": "Авторизован как %s" -} \ No newline at end of file +} diff --git a/internal/model/integration.go b/internal/model/integration.go index 8f7a59e8..5311b04e 100644 --- a/internal/model/integration.go +++ b/internal/model/integration.go @@ -90,6 +90,7 @@ type Integration struct { WebhookSecret string RSSBridgeEnabled bool RSSBridgeURL string + RSSBridgeToken string OmnivoreEnabled bool OmnivoreAPIKey string OmnivoreURL string diff --git a/internal/reader/subscription/finder.go b/internal/reader/subscription/finder.go index 3e00170f..24973ea3 100644 --- a/internal/reader/subscription/finder.go +++ b/internal/reader/subscription/finder.go @@ -48,7 +48,7 @@ func (f *SubscriptionFinder) FeedResponseInfo() *model.FeedCreationRequestFromSu return f.feedResponseInfo } -func (f *SubscriptionFinder) FindSubscriptions(websiteURL, rssBridgeURL string) (Subscriptions, *locale.LocalizedErrorWrapper) { +func (f *SubscriptionFinder) FindSubscriptions(websiteURL, rssBridgeURL string, rssBridgeToken string) (Subscriptions, *locale.LocalizedErrorWrapper) { responseHandler := fetcher.NewResponseHandler(f.requestBuilder.ExecuteRequest(websiteURL)) defer responseHandler.Close() @@ -108,7 +108,7 @@ func (f *SubscriptionFinder) FindSubscriptions(websiteURL, rssBridgeURL string) // Step 5) Check if the website URL can use RSS-Bridge. if rssBridgeURL != "" { slog.Debug("Try to detect feeds with RSS-Bridge", slog.String("website_url", websiteURL)) - if subscriptions, localizedError := f.FindSubscriptionsFromRSSBridge(websiteURL, rssBridgeURL); localizedError != nil { + if subscriptions, localizedError := f.FindSubscriptionsFromRSSBridge(websiteURL, rssBridgeURL, rssBridgeToken); localizedError != nil { return nil, localizedError } else if len(subscriptions) > 0 { slog.Debug("Subscriptions found from RSS-Bridge", slog.String("website_url", websiteURL), slog.Any("subscriptions", subscriptions)) @@ -254,13 +254,14 @@ func (f *SubscriptionFinder) FindSubscriptionsFromWellKnownURLs(websiteURL strin return subscriptions, nil } -func (f *SubscriptionFinder) FindSubscriptionsFromRSSBridge(websiteURL, rssBridgeURL string) (Subscriptions, *locale.LocalizedErrorWrapper) { +func (f *SubscriptionFinder) FindSubscriptionsFromRSSBridge(websiteURL, rssBridgeURL string, rssBridgeToken string) (Subscriptions, *locale.LocalizedErrorWrapper) { slog.Debug("Trying to detect feeds using RSS-Bridge", slog.String("website_url", websiteURL), slog.String("rssbridge_url", rssBridgeURL), + slog.String("rssbridge_token", rssBridgeToken), ) - bridges, err := rssbridge.DetectBridges(rssBridgeURL, websiteURL) + bridges, err := rssbridge.DetectBridges(rssBridgeURL, rssBridgeToken, websiteURL) if err != nil { return nil, locale.NewLocalizedErrorWrapper(err, "error.unable_to_detect_rssbridge", err) } @@ -268,6 +269,7 @@ func (f *SubscriptionFinder) FindSubscriptionsFromRSSBridge(websiteURL, rssBridg slog.Debug("RSS-Bridge results", slog.String("website_url", websiteURL), slog.String("rssbridge_url", rssBridgeURL), + slog.String("rssbridge_token", rssBridgeToken), slog.Int("nb_bridges", len(bridges)), ) diff --git a/internal/storage/integration.go b/internal/storage/integration.go index 786a3c12..4ab85861 100644 --- a/internal/storage/integration.go +++ b/internal/storage/integration.go @@ -219,7 +219,8 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) { pushover_user, pushover_token, pushover_device, - pushover_prefix + pushover_prefix, + rssbridge_token FROM integrations WHERE @@ -338,6 +339,7 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) { &integration.PushoverToken, &integration.PushoverDevice, &integration.PushoverPrefix, + &integration.RSSBridgeToken, ) switch { case err == sql.ErrNoRows: @@ -464,9 +466,10 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error { pushover_user=$107, pushover_token=$108, pushover_device=$109, - pushover_prefix=$110 + pushover_prefix=$110, + rssbridge_token=$111 WHERE - user_id=$111 + user_id=$112 ` _, err := s.db.Exec( query, @@ -580,6 +583,7 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error { integration.PushoverToken, integration.PushoverDevice, integration.PushoverPrefix, + integration.RSSBridgeToken, integration.UserID, ) diff --git a/internal/template/templates/views/integrations.html b/internal/template/templates/views/integrations.html index 7eeb0a12..86948f06 100644 --- a/internal/template/templates/views/integrations.html +++ b/internal/template/templates/views/integrations.html @@ -513,6 +513,9 @@ + + +
diff --git a/internal/ui/form/integration.go b/internal/ui/form/integration.go index 5a8ef9f1..09c2a5f2 100644 --- a/internal/ui/form/integration.go +++ b/internal/ui/form/integration.go @@ -93,6 +93,7 @@ type IntegrationForm struct { WebhookSecret string RSSBridgeEnabled bool RSSBridgeURL string + RSSBridgeToken string OmnivoreEnabled bool OmnivoreAPIKey string OmnivoreURL string @@ -204,6 +205,7 @@ func (i IntegrationForm) Merge(integration *model.Integration) { integration.WebhookURL = i.WebhookURL integration.RSSBridgeEnabled = i.RSSBridgeEnabled integration.RSSBridgeURL = i.RSSBridgeURL + integration.RSSBridgeToken = i.RSSBridgeToken integration.OmnivoreEnabled = i.OmnivoreEnabled integration.OmnivoreAPIKey = i.OmnivoreAPIKey integration.OmnivoreURL = i.OmnivoreURL @@ -318,6 +320,7 @@ func NewIntegrationForm(r *http.Request) *IntegrationForm { WebhookURL: r.FormValue("webhook_url"), RSSBridgeEnabled: r.FormValue("rssbridge_enabled") == "1", RSSBridgeURL: r.FormValue("rssbridge_url"), + RSSBridgeToken: r.FormValue("rssbridge_token"), OmnivoreEnabled: r.FormValue("omnivore_enabled") == "1", OmnivoreAPIKey: r.FormValue("omnivore_api_key"), OmnivoreURL: r.FormValue("omnivore_url"), diff --git a/internal/ui/integration_show.go b/internal/ui/integration_show.go index 05fc7ca5..57ef3400 100644 --- a/internal/ui/integration_show.go +++ b/internal/ui/integration_show.go @@ -107,6 +107,7 @@ func (h *handler) showIntegrationPage(w http.ResponseWriter, r *http.Request) { WebhookSecret: integration.WebhookSecret, RSSBridgeEnabled: integration.RSSBridgeEnabled, RSSBridgeURL: integration.RSSBridgeURL, + RSSBridgeToken: integration.RSSBridgeToken, OmnivoreEnabled: integration.OmnivoreEnabled, OmnivoreAPIKey: integration.OmnivoreAPIKey, OmnivoreURL: integration.OmnivoreURL, diff --git a/internal/ui/subscription_submit.go b/internal/ui/subscription_submit.go index 16a9c3f0..93665cc5 100644 --- a/internal/ui/subscription_submit.go +++ b/internal/ui/subscription_submit.go @@ -53,8 +53,10 @@ func (h *handler) submitSubscription(w http.ResponseWriter, r *http.Request) { } var rssBridgeURL string + var rssBridgeToken string if intg, err := h.store.Integration(user.ID); err == nil && intg != nil && intg.RSSBridgeEnabled { rssBridgeURL = intg.RSSBridgeURL + rssBridgeToken = intg.RSSBridgeToken } requestBuilder := fetcher.NewRequestBuilder() @@ -73,6 +75,7 @@ func (h *handler) submitSubscription(w http.ResponseWriter, r *http.Request) { subscriptions, localizedError := subscriptionFinder.FindSubscriptions( subscriptionForm.URL, rssBridgeURL, + rssBridgeToken, ) if localizedError != nil { v.Set("form", subscriptionForm)