Redirect to login page if require-login is enabled
This commit is contained in:
@@ -172,6 +172,7 @@ func execServe(c *cli.Context) error {
|
|||||||
webRoot := c.String("web-root")
|
webRoot := c.String("web-root")
|
||||||
enableSignup := c.Bool("enable-signup")
|
enableSignup := c.Bool("enable-signup")
|
||||||
enableLogin := c.Bool("enable-login")
|
enableLogin := c.Bool("enable-login")
|
||||||
|
requireLogin := c.Bool("require-login")
|
||||||
enableReservations := c.Bool("enable-reservations")
|
enableReservations := c.Bool("enable-reservations")
|
||||||
upstreamBaseURL := c.String("upstream-base-url")
|
upstreamBaseURL := c.String("upstream-base-url")
|
||||||
upstreamAccessToken := c.String("upstream-access-token")
|
upstreamAccessToken := c.String("upstream-access-token")
|
||||||
@@ -476,6 +477,7 @@ func execServe(c *cli.Context) error {
|
|||||||
conf.BillingContact = billingContact
|
conf.BillingContact = billingContact
|
||||||
conf.EnableSignup = enableSignup
|
conf.EnableSignup = enableSignup
|
||||||
conf.EnableLogin = enableLogin
|
conf.EnableLogin = enableLogin
|
||||||
|
conf.RequireLogin = requireLogin
|
||||||
conf.EnableReservations = enableReservations
|
conf.EnableReservations = enableReservations
|
||||||
conf.EnableMetrics = enableMetrics
|
conf.EnableMetrics = enableMetrics
|
||||||
conf.MetricsListenHTTP = metricsListenHTTP
|
conf.MetricsListenHTTP = metricsListenHTTP
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ type Config struct {
|
|||||||
BillingContact string
|
BillingContact string
|
||||||
EnableSignup bool // Enable creation of accounts via API and UI
|
EnableSignup bool // Enable creation of accounts via API and UI
|
||||||
EnableLogin bool
|
EnableLogin bool
|
||||||
|
RequireLogin bool
|
||||||
EnableReservations bool // Allow users with role "user" to own/reserve topics
|
EnableReservations bool // Allow users with role "user" to own/reserve topics
|
||||||
EnableMetrics bool
|
EnableMetrics bool
|
||||||
AccessControlAllowOrigin string // CORS header field to restrict access from web clients
|
AccessControlAllowOrigin string // CORS header field to restrict access from web clients
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
"heckel.io/ntfy/v2/payments"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -33,7 +31,9 @@ import (
|
|||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
"heckel.io/ntfy/v2/log"
|
"heckel.io/ntfy/v2/log"
|
||||||
|
"heckel.io/ntfy/v2/payments"
|
||||||
"heckel.io/ntfy/v2/user"
|
"heckel.io/ntfy/v2/user"
|
||||||
"heckel.io/ntfy/v2/util"
|
"heckel.io/ntfy/v2/util"
|
||||||
"heckel.io/ntfy/v2/util/sprig"
|
"heckel.io/ntfy/v2/util/sprig"
|
||||||
@@ -600,12 +600,12 @@ func (s *Server) handleWebConfig(w http.ResponseWriter, _ *http.Request, _ *visi
|
|||||||
BaseURL: "", // Will translate to window.location.origin
|
BaseURL: "", // Will translate to window.location.origin
|
||||||
AppRoot: s.config.WebRoot,
|
AppRoot: s.config.WebRoot,
|
||||||
EnableLogin: s.config.EnableLogin,
|
EnableLogin: s.config.EnableLogin,
|
||||||
|
RequireLogin: s.config.RequireLogin,
|
||||||
EnableSignup: s.config.EnableSignup,
|
EnableSignup: s.config.EnableSignup,
|
||||||
EnablePayments: s.config.StripeSecretKey != "",
|
EnablePayments: s.config.StripeSecretKey != "",
|
||||||
EnableCalls: s.config.TwilioAccount != "",
|
EnableCalls: s.config.TwilioAccount != "",
|
||||||
EnableEmails: s.config.SMTPSenderFrom != "",
|
EnableEmails: s.config.SMTPSenderFrom != "",
|
||||||
EnableReservations: s.config.EnableReservations,
|
EnableReservations: s.config.EnableReservations,
|
||||||
ReuqireLogin: s.config.RequireLogin,
|
|
||||||
EnableWebPush: s.config.WebPushPublicKey != "",
|
EnableWebPush: s.config.WebPushPublicKey != "",
|
||||||
BillingContact: s.config.BillingContact,
|
BillingContact: s.config.BillingContact,
|
||||||
WebPushPublicKey: s.config.WebPushPublicKey,
|
WebPushPublicKey: s.config.WebPushPublicKey,
|
||||||
|
|||||||
@@ -449,13 +449,13 @@ type apiConfigResponse struct {
|
|||||||
BaseURL string `json:"base_url"`
|
BaseURL string `json:"base_url"`
|
||||||
AppRoot string `json:"app_root"`
|
AppRoot string `json:"app_root"`
|
||||||
EnableLogin bool `json:"enable_login"`
|
EnableLogin bool `json:"enable_login"`
|
||||||
|
RequireLogin bool `json:"require_login"`
|
||||||
EnableSignup bool `json:"enable_signup"`
|
EnableSignup bool `json:"enable_signup"`
|
||||||
EnablePayments bool `json:"enable_payments"`
|
EnablePayments bool `json:"enable_payments"`
|
||||||
EnableCalls bool `json:"enable_calls"`
|
EnableCalls bool `json:"enable_calls"`
|
||||||
EnableEmails bool `json:"enable_emails"`
|
EnableEmails bool `json:"enable_emails"`
|
||||||
EnableReservations bool `json:"enable_reservations"`
|
EnableReservations bool `json:"enable_reservations"`
|
||||||
EnableWebPush bool `json:"enable_web_push"`
|
EnableWebPush bool `json:"enable_web_push"`
|
||||||
RequireLogin bool `json:"require_login"`
|
|
||||||
BillingContact string `json:"billing_contact"`
|
BillingContact string `json:"billing_contact"`
|
||||||
WebPushPublicKey string `json:"web_push_public_key"`
|
WebPushPublicKey string `json:"web_push_public_key"`
|
||||||
DisallowedTopics []string `json:"disallowed_topics"`
|
DisallowedTopics []string `json:"disallowed_topics"`
|
||||||
|
|||||||
@@ -97,8 +97,6 @@
|
|||||||
"notifications_none_for_any_description": "To send notifications to a topic, simply PUT or POST to the topic URL. Here's an example using one of your topics.",
|
"notifications_none_for_any_description": "To send notifications to a topic, simply PUT or POST to the topic URL. Here's an example using one of your topics.",
|
||||||
"notifications_no_subscriptions_title": "It looks like you don't have any subscriptions yet.",
|
"notifications_no_subscriptions_title": "It looks like you don't have any subscriptions yet.",
|
||||||
"notifications_no_subscriptions_description": "Click the \"{{linktext}}\" link to create or subscribe to a topic. After that, you can send messages via PUT or POST and you'll receive notifications here.",
|
"notifications_no_subscriptions_description": "Click the \"{{linktext}}\" link to create or subscribe to a topic. After that, you can send messages via PUT or POST and you'll receive notifications here.",
|
||||||
"notifications_no_subscriptions_login_title": "This page requires a Login.",
|
|
||||||
"notifications_no_subscriptions_login_description": "Click \"{{linktext}}\" to login into your account.",
|
|
||||||
"notifications_example": "Example",
|
"notifications_example": "Example",
|
||||||
"notifications_more_details": "For more information, check out the <websiteLink>website</websiteLink> or <docsLink>documentation</docsLink>.",
|
"notifications_more_details": "For more information, check out the <websiteLink>website</websiteLink> or <docsLink>documentation</docsLink>.",
|
||||||
"display_name_dialog_title": "Change display name",
|
"display_name_dialog_title": "Change display name",
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ const NavList = (props) => {
|
|||||||
{showNotificationContextNotSupportedBox && <NotificationContextNotSupportedAlert />}
|
{showNotificationContextNotSupportedBox && <NotificationContextNotSupportedAlert />}
|
||||||
{showNotificationIOSInstallRequired && <NotificationIOSInstallRequiredAlert />}
|
{showNotificationIOSInstallRequired && <NotificationIOSInstallRequiredAlert />}
|
||||||
{alertVisible && <Divider />}
|
{alertVisible && <Divider />}
|
||||||
{!showSubscriptionsList && (session.exists() || !config.require_login) && (
|
{!showSubscriptionsList && (
|
||||||
<ListItemButton onClick={() => navigate(routes.app)} selected={location.pathname === config.app_root}>
|
<ListItemButton onClick={() => navigate(routes.app)} selected={location.pathname === config.app_root}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<ChatBubble />
|
<ChatBubble />
|
||||||
@@ -164,36 +164,30 @@ const NavList = (props) => {
|
|||||||
<ListItemText primary={t("nav_button_account")} />
|
<ListItemText primary={t("nav_button_account")} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
)}
|
)}
|
||||||
{session.exists() || !config.require_login && (
|
|
||||||
<ListItemButton onClick={() => navigate(routes.settings)} selected={location.pathname === routes.settings}>
|
<ListItemButton onClick={() => navigate(routes.settings)} selected={location.pathname === routes.settings}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={t("nav_button_settings")} />
|
<ListItemText primary={t("nav_button_settings")} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
)}
|
|
||||||
<ListItemButton onClick={() => openUrl("/docs")}>
|
<ListItemButton onClick={() => openUrl("/docs")}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<ArticleIcon />
|
<ArticleIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={t("nav_button_documentation")} />
|
<ListItemText primary={t("nav_button_documentation")} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
{session.exists() || !config.require_login && (
|
|
||||||
<ListItemButton onClick={() => props.onPublishMessageClick()}>
|
<ListItemButton onClick={() => props.onPublishMessageClick()}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Send />
|
<Send />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={t("nav_button_publish_message")} />
|
<ListItemText primary={t("nav_button_publish_message")} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
)}
|
|
||||||
{session.exists() || !config.require_login && (
|
|
||||||
<ListItemButton onClick={() => setSubscribeDialogOpen(true)}>
|
<ListItemButton onClick={() => setSubscribeDialogOpen(true)}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<AddIcon />
|
<AddIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={t("nav_button_subscribe")} />
|
<ListItemText primary={t("nav_button_subscribe")} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
)}
|
|
||||||
{showUpgradeBanner && (
|
{showUpgradeBanner && (
|
||||||
// The text background gradient didn't seem to do well with switching between light/dark mode,
|
// The text background gradient didn't seem to do well with switching between light/dark mode,
|
||||||
// So adding a `key` forces React to replace the entire component when the theme changes
|
// So adding a `key` forces React to replace the entire component when the theme changes
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ import priority5 from "../img/priority-5.svg";
|
|||||||
import logoOutline from "../img/ntfy-outline.svg";
|
import logoOutline from "../img/ntfy-outline.svg";
|
||||||
import AttachmentIcon from "./AttachmentIcon";
|
import AttachmentIcon from "./AttachmentIcon";
|
||||||
import { useAutoSubscribe } from "./hooks";
|
import { useAutoSubscribe } from "./hooks";
|
||||||
import session from "../app/Session";
|
|
||||||
|
|
||||||
const priorityFiles = {
|
const priorityFiles = {
|
||||||
1: priority1,
|
1: priority1,
|
||||||
@@ -645,16 +644,12 @@ const NoSubscriptions = () => {
|
|||||||
<Typography variant="h5" align="center" sx={{ paddingBottom: 1 }}>
|
<Typography variant="h5" align="center" sx={{ paddingBottom: 1 }}>
|
||||||
<img src={logoOutline} height="64" width="64" alt={t("action_bar_logo_alt")} />
|
<img src={logoOutline} height="64" width="64" alt={t("action_bar_logo_alt")} />
|
||||||
<br />
|
<br />
|
||||||
{!session.exists() && !config.require_login && t("notifications_no_subscriptions_title")}
|
{t("notifications_no_subscriptions_title")}
|
||||||
{!session.exists() && config.require_login && t("notifications_no_subscriptions_login_title")}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Paragraph>
|
<Paragraph>
|
||||||
{!session.exists() && !config.require_login && t("notifications_no_subscriptions_description", {
|
{t("notifications_no_subscriptions_description", {
|
||||||
linktext: t("nav_button_subscribe"),
|
linktext: t("nav_button_subscribe"),
|
||||||
})}
|
})}
|
||||||
{!session.exists() && config.require_login && t("notifications_no_subscriptions_login_description", {
|
|
||||||
linktext: t("action_bar_sign_in"),
|
|
||||||
})}
|
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
<Paragraph>
|
<Paragraph>
|
||||||
<ForMoreDetails />
|
<ForMoreDetails />
|
||||||
|
|||||||
@@ -65,22 +65,16 @@ const maybeUpdateAccountSettings = async (payload) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Preferences = () => {
|
const Preferences = () => (
|
||||||
if (!session.exists() or !config.requireLogin) {
|
<Container maxWidth="md" sx={{ marginTop: 3, marginBottom: 3 }}>
|
||||||
window.location.href = routes.app;
|
<Stack spacing={3}>
|
||||||
return <></>;
|
<Notifications />
|
||||||
}
|
<Reservations />
|
||||||
return (
|
<Users />
|
||||||
<Container maxWidth="md" sx={{ marginTop: 3, marginBottom: 3 }}>
|
<Appearance />
|
||||||
<Stack spacing={3}>
|
</Stack>
|
||||||
<Notifications />
|
</Container>
|
||||||
<Reservations />
|
);
|
||||||
<Users />
|
|
||||||
<Appearance />
|
|
||||||
</Stack>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Notifications = () => {
|
const Notifications = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|||||||
Reference in New Issue
Block a user