diff --git a/.golangci.yml b/.golangci.yml
index daa4d0595..dcf979fba 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -8,7 +8,7 @@ linters-settings:
lines: 100
statements: 50
gci:
- local-prefixes: github.com/pomerium/pomerium
+ local-prefixes: github.com/pomerium
goconst:
min-len: 2
min-occurrences: 2
@@ -28,7 +28,7 @@ linters-settings:
gocyclo:
min-complexity: 15
goimports:
- local-prefixes: github.com/pomerium/pomerium
+ local-prefixes: github.com/pomerium
govet:
check-shadowing: false
lll:
diff --git a/authenticate/handlers.go b/authenticate/handlers.go
index 07648647d..330769209 100644
--- a/authenticate/handlers.go
+++ b/authenticate/handlers.go
@@ -12,11 +12,11 @@ import (
"github.com/google/uuid"
"github.com/gorilla/mux"
- "github.com/pomerium/csrf"
"github.com/rs/cors"
"golang.org/x/oauth2"
"google.golang.org/protobuf/types/known/timestamppb"
+ "github.com/pomerium/csrf"
"github.com/pomerium/pomerium/authenticate/handlers"
"github.com/pomerium/pomerium/authenticate/handlers/webauthn"
"github.com/pomerium/pomerium/internal/httputil"
@@ -55,8 +55,7 @@ func (a *Authenticate) Mount(r *mux.Router) {
csrf.Path("/"),
csrf.UnsafePaths(
[]string{
- "/oauth2/callback", // rfc6749#section-10.12 accepts GET
- "/.pomerium/sign_out", // https://openid.net/specs/openid-connect-frontchannel-1_0.html
+ "/oauth2/callback", // rfc6749#section-10.12 accepts GET
}),
csrf.FormValueName("state"), // rfc6749#section-10.12
csrf.CookieName(csrfKey),
@@ -96,14 +95,10 @@ func (a *Authenticate) mountDashboard(r *mux.Router) {
sr.Use(a.VerifySession)
sr.Path("/").Handler(a.requireValidSignatureOnRedirect(a.userInfo))
sr.Path("/sign_in").Handler(a.requireValidSignature(a.SignIn))
- sr.Path("/sign_out").Handler(a.requireValidSignature(a.SignOut))
+ sr.Path("/sign_out").Handler(httputil.HandlerFunc(a.SignOut))
sr.Path("/webauthn").Handler(webauthn.New(a.getWebauthnState))
sr.Path("/device-enrolled").Handler(httputil.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
- authenticateURL, err := a.options.Load().GetAuthenticateURL()
- if err != nil {
- return err
- }
- handlers.DeviceEnrolled(authenticateURL, a.state.Load().sharedKey).ServeHTTP(w, r)
+ handlers.DeviceEnrolled().ServeHTTP(w, r)
return nil
}))
@@ -276,6 +271,25 @@ func (a *Authenticate) SignIn(w http.ResponseWriter, r *http.Request) error {
// SignOut signs the user out and attempts to revoke the user's identity session
// Handles both GET and POST.
func (a *Authenticate) SignOut(w http.ResponseWriter, r *http.Request) error {
+ // check for an HMAC'd URL. If none is found, show a confirmation page.
+ err := middleware.ValidateRequestURL(a.getExternalRequest(r), a.state.Load().sharedKey)
+ if err != nil {
+ authenticateURL, err := a.options.Load().GetAuthenticateURL()
+ if err != nil {
+ return err
+ }
+
+ handlers.SignOutConfirm(handlers.SignOutConfirmData{
+ URL: urlutil.SignOutURL(r, authenticateURL, a.state.Load().sharedKey),
+ }).ServeHTTP(w, r)
+ return nil
+ }
+
+ // otherwise actually do the sign out
+ return a.signOutRedirect(w, r)
+}
+
+func (a *Authenticate) signOutRedirect(w http.ResponseWriter, r *http.Request) error {
ctx, span := trace.StartSpan(r.Context(), "authenticate.SignOut")
defer span.End()
@@ -553,7 +567,6 @@ func (a *Authenticate) userInfo(w http.ResponseWriter, r *http.Request) error {
DirectoryUser: pbDirectoryUser,
IsImpersonated: isImpersonated,
Session: pbSession,
- SignOutURL: urlutil.SignOutURL(r, authenticateURL, state.sharedKey),
User: pbUser,
WebAuthnURL: urlutil.WebAuthnURL(r, authenticateURL, state.sharedKey, r.URL.Query()),
}).ServeHTTP(w, r)
diff --git a/authenticate/handlers/device-enrolled.go b/authenticate/handlers/device-enrolled.go
index fcb3d885b..604be4af2 100644
--- a/authenticate/handlers/device-enrolled.go
+++ b/authenticate/handlers/device-enrolled.go
@@ -2,18 +2,14 @@ package handlers
import (
"net/http"
- "net/url"
"github.com/pomerium/pomerium/internal/httputil"
- "github.com/pomerium/pomerium/internal/urlutil"
"github.com/pomerium/pomerium/ui"
)
// DeviceEnrolled displays an HTML page informing the user that they've successfully enrolled a device.
-func DeviceEnrolled(authenticateURL *url.URL, sharedKey []byte) http.Handler {
+func DeviceEnrolled() http.Handler {
return httputil.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
- return ui.ServePage(w, r, "DeviceEnrolled", map[string]interface{}{
- "signOutUrl": urlutil.SignOutURL(r, authenticateURL, sharedKey),
- })
+ return ui.ServePage(w, r, "DeviceEnrolled", map[string]interface{}{})
})
}
diff --git a/authenticate/handlers/signout.go b/authenticate/handlers/signout.go
new file mode 100644
index 000000000..db2b0aac3
--- /dev/null
+++ b/authenticate/handlers/signout.go
@@ -0,0 +1,27 @@
+package handlers
+
+import (
+ "net/http"
+
+ "github.com/pomerium/pomerium/internal/httputil"
+ "github.com/pomerium/pomerium/ui"
+)
+
+// SignOutConfirmData is the data for the SignOutConfirm page.
+type SignOutConfirmData struct {
+ URL string
+}
+
+// ToJSON converts the data into a JSON map.
+func (data SignOutConfirmData) ToJSON() map[string]interface{} {
+ return map[string]interface{}{
+ "url": data.URL,
+ }
+}
+
+// SignOutConfirm returns a handler that renders the sign out confirm page.
+func SignOutConfirm(data SignOutConfirmData) http.Handler {
+ return httputil.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
+ return ui.ServePage(w, r, "SignOutConfirm", data.ToJSON())
+ })
+}
diff --git a/authenticate/handlers/userinfo.go b/authenticate/handlers/userinfo.go
index 54ff9bd38..5ec61e6c4 100644
--- a/authenticate/handlers/userinfo.go
+++ b/authenticate/handlers/userinfo.go
@@ -20,7 +20,6 @@ type UserInfoData struct {
DirectoryUser *directory.User
IsImpersonated bool
Session *session.Session
- SignOutURL string
User *user.User
WebAuthnURL string
}
@@ -43,7 +42,6 @@ func (data UserInfoData) ToJSON() map[string]interface{} {
if bs, err := protojson.Marshal(data.Session); err == nil {
m["session"] = json.RawMessage(bs)
}
- m["signOutUrl"] = data.SignOutURL
if bs, err := protojson.Marshal(data.User); err == nil {
m["user"] = json.RawMessage(bs)
}
diff --git a/authenticate/handlers/webauthn/webauthn.go b/authenticate/handlers/webauthn/webauthn.go
index 8d6d73879..00655321e 100644
--- a/authenticate/handlers/webauthn/webauthn.go
+++ b/authenticate/handlers/webauthn/webauthn.go
@@ -13,7 +13,6 @@ import (
"net/url"
"github.com/google/uuid"
- "github.com/pomerium/webauthn"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
@@ -30,6 +29,7 @@ import (
"github.com/pomerium/pomerium/pkg/grpc/user"
"github.com/pomerium/pomerium/pkg/webauthnutil"
"github.com/pomerium/pomerium/ui"
+ "github.com/pomerium/webauthn"
)
const maxAuthenticateResponses = 5
@@ -373,7 +373,6 @@ func (h *Handler) handleView(w http.ResponseWriter, r *http.Request, state *Stat
"creationOptions": creationOptions,
"requestOptions": requestOptions,
"selfUrl": r.URL.String(),
- "signOutUrl": urlutil.SignOutURL(r, state.AuthenticateURL, state.SharedKey),
})
}
diff --git a/authenticate/handlers_test.go b/authenticate/handlers_test.go
index b3312fc7e..4002e6bde 100644
--- a/authenticate/handlers_test.go
+++ b/authenticate/handlers_test.go
@@ -227,12 +227,84 @@ func TestAuthenticate_SignOut(t *testing.T) {
wantCode int
wantBody string
}{
- {"good post", http.MethodPost, nil, "https://corp.pomerium.io/", "", "sig", "ts", identity.MockProvider{LogOutResponse: (*uriParseHelper("https://microsoft.com"))}, &mstore.Store{Encrypted: true, Session: &sessions.State{}}, http.StatusFound, ""},
- {"signout redirect url", http.MethodPost, nil, "", "https://signout-redirect-url.example.com", "sig", "ts", identity.MockProvider{LogOutResponse: (*uriParseHelper("https://microsoft.com"))}, &mstore.Store{Encrypted: true, Session: &sessions.State{}}, http.StatusFound, ""},
- {"failed revoke", http.MethodPost, nil, "https://corp.pomerium.io/", "", "sig", "ts", identity.MockProvider{RevokeError: errors.New("OH NO")}, &mstore.Store{Encrypted: true, Session: &sessions.State{}}, http.StatusFound, ""},
- {"load session error", http.MethodPost, errors.New("error"), "https://corp.pomerium.io/", "", "sig", "ts", identity.MockProvider{RevokeError: errors.New("OH NO")}, &mstore.Store{Encrypted: true, Session: &sessions.State{}}, http.StatusFound, ""},
- {"bad redirect uri", http.MethodPost, nil, "corp.pomerium.io/", "", "sig", "ts", identity.MockProvider{LogOutError: oidc.ErrSignoutNotImplemented}, &mstore.Store{Encrypted: true, Session: &sessions.State{}}, http.StatusFound, ""},
- {"no redirect uri", http.MethodPost, nil, "", "", "sig", "ts", identity.MockProvider{LogOutResponse: (*uriParseHelper("https://microsoft.com"))}, &mstore.Store{Encrypted: true, Session: &sessions.State{}}, http.StatusOK, "{\"Status\":200,\"Error\":\"OK: user logged out\"}\n"},
+ {
+ "good post",
+ http.MethodPost,
+ nil,
+ "https://corp.pomerium.io/",
+ "",
+ "sig",
+ "ts",
+ identity.MockProvider{LogOutResponse: (*uriParseHelper("https://microsoft.com"))},
+ &mstore.Store{Encrypted: true, Session: &sessions.State{}},
+ http.StatusFound,
+ "",
+ },
+ {
+ "signout redirect url",
+ http.MethodPost,
+ nil,
+ "",
+ "https://signout-redirect-url.example.com",
+ "sig",
+ "ts",
+ identity.MockProvider{LogOutResponse: (*uriParseHelper("https://microsoft.com"))},
+ &mstore.Store{Encrypted: true, Session: &sessions.State{}},
+ http.StatusFound,
+ "",
+ },
+ {
+ "failed revoke",
+ http.MethodPost,
+ nil,
+ "https://corp.pomerium.io/",
+ "",
+ "sig",
+ "ts",
+ identity.MockProvider{RevokeError: errors.New("OH NO")},
+ &mstore.Store{Encrypted: true, Session: &sessions.State{}},
+ http.StatusFound,
+ "",
+ },
+ {
+ "load session error",
+ http.MethodPost,
+ errors.New("error"),
+ "https://corp.pomerium.io/",
+ "",
+ "sig",
+ "ts",
+ identity.MockProvider{RevokeError: errors.New("OH NO")},
+ &mstore.Store{Encrypted: true, Session: &sessions.State{}},
+ http.StatusFound,
+ "",
+ },
+ {
+ "bad redirect uri",
+ http.MethodPost,
+ nil,
+ "corp.pomerium.io/",
+ "",
+ "sig",
+ "ts",
+ identity.MockProvider{LogOutError: oidc.ErrSignoutNotImplemented},
+ &mstore.Store{Encrypted: true, Session: &sessions.State{}},
+ http.StatusFound,
+ "",
+ },
+ {
+ "no redirect uri",
+ http.MethodPost,
+ nil,
+ "",
+ "",
+ "sig",
+ "ts",
+ identity.MockProvider{LogOutResponse: (*uriParseHelper("https://microsoft.com"))},
+ &mstore.Store{Encrypted: true, Session: &sessions.State{}},
+ http.StatusOK,
+ "{\"Status\":200,\"Error\":\"OK: user logged out\"}\n",
+ },
}
for _, tt := range tests {
tt := tt
@@ -295,7 +367,7 @@ func TestAuthenticate_SignOut(t *testing.T) {
r.Header.Set("Accept", "application/json")
w := httptest.NewRecorder()
- httputil.HandlerFunc(a.SignOut).ServeHTTP(w, r)
+ httputil.HandlerFunc(a.signOutRedirect).ServeHTTP(w, r)
if status := w.Code; status != tt.wantCode {
t.Errorf("handler returned wrong status code: got %v want %v", status, tt.wantCode)
}
@@ -727,89 +799,6 @@ func (m mockDirectoryServiceClient) RefreshUser(ctx context.Context, in *directo
return nil, status.Error(codes.Unimplemented, "")
}
-func TestAuthenticate_SignOut_CSRF(t *testing.T) {
- now := time.Now()
- signer, err := jws.NewHS256Signer(nil)
- if err != nil {
- t.Fatal(err)
- }
- pbNow, _ := ptypes.TimestampProto(now)
- a := &Authenticate{
- options: config.NewAtomicOptions(),
- state: newAtomicAuthenticateState(&authenticateState{
- // sessionStore: tt.sessionStore,
- cookieSecret: cryptutil.NewKey(),
- encryptedEncoder: signer,
- sharedEncoder: signer,
- dataBrokerClient: mockDataBrokerServiceClient{
- get: func(ctx context.Context, in *databroker.GetRequest, opts ...grpc.CallOption) (*databroker.GetResponse, error) {
- data, err := ptypes.MarshalAny(&session.Session{
- Id: "SESSION_ID",
- UserId: "USER_ID",
- IdToken: &session.IDToken{IssuedAt: pbNow},
- })
- if err != nil {
- return nil, err
- }
-
- return &databroker.GetResponse{
- Record: &databroker.Record{
- Version: 1,
- Type: data.GetTypeUrl(),
- Id: "SESSION_ID",
- Data: data,
- },
- }, nil
- },
- },
- directoryClient: new(mockDirectoryServiceClient),
- }),
- }
- tests := []struct {
- name string
- setCSRFCookie bool
- method string
- wantStatus int
- wantBody string
- }{
- {"GET without CSRF should fail", false, "GET", 400, "{\"Status\":400,\"Error\":\"Bad Request: CSRF token invalid\"}\n"},
- {"POST without CSRF should fail", false, "POST", 400, "{\"Status\":400,\"Error\":\"Bad Request: CSRF token invalid\"}\n"},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- s := a.Handler()
-
- // Obtain a CSRF cookie via a GET request.
- orr, err := http.NewRequest("GET", "/", nil)
- if err != nil {
- t.Fatal(err)
- }
- rr := httptest.NewRecorder()
- s.ServeHTTP(rr, orr)
-
- r, err := http.NewRequest(tt.method, "/.pomerium/sign_out", nil)
- if err != nil {
- t.Fatal(err)
- }
- if tt.setCSRFCookie {
- r.Header.Set("Cookie", rr.Header().Get("Set-Cookie"))
- }
- r.Header.Set("Accept", "application/json")
- r.Header.Set("Referer", "/")
- rr = httptest.NewRecorder()
- s.ServeHTTP(rr, r)
-
- if rr.Code != tt.wantStatus {
- t.Errorf("status: got %v want %v", rr.Code, tt.wantStatus)
- }
- body := rr.Body.String()
- if diff := cmp.Diff(body, tt.wantBody); diff != "" {
- t.Errorf("handler returned wrong body Body: %s", diff)
- }
- })
- }
-}
-
func mustParseURL(rawurl string) *url.URL {
u, err := url.Parse(rawurl)
if err != nil {
diff --git a/authenticate/state.go b/authenticate/state.go
index dfbd02a65..c63f25096 100644
--- a/authenticate/state.go
+++ b/authenticate/state.go
@@ -9,7 +9,6 @@ import (
"sync/atomic"
"github.com/go-jose/go-jose/v3"
- "github.com/pomerium/webauthn"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/encoding"
@@ -24,6 +23,7 @@ import (
"github.com/pomerium/pomerium/pkg/grpc/databroker"
"github.com/pomerium/pomerium/pkg/grpc/directory"
"github.com/pomerium/pomerium/pkg/webauthnutil"
+ "github.com/pomerium/webauthn"
)
var outboundGRPCConnection = new(grpc.CachedOutboundGRPClientConn)
diff --git a/internal/httputil/router.go b/internal/httputil/router.go
index 1dec755fd..d4273c751 100644
--- a/internal/httputil/router.go
+++ b/internal/httputil/router.go
@@ -4,8 +4,8 @@ import (
"net/http"
"github.com/gorilla/mux"
- "github.com/pomerium/csrf"
+ "github.com/pomerium/csrf"
"github.com/pomerium/pomerium/ui"
)
diff --git a/pkg/webauthnutil/credential_storage.go b/pkg/webauthnutil/credential_storage.go
index feb24dad7..84a520ba1 100644
--- a/pkg/webauthnutil/credential_storage.go
+++ b/pkg/webauthnutil/credential_storage.go
@@ -3,13 +3,13 @@ package webauthnutil
import (
"context"
- "github.com/pomerium/webauthn"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/pomerium/pomerium/pkg/encoding/base58"
"github.com/pomerium/pomerium/pkg/grpc/databroker"
"github.com/pomerium/pomerium/pkg/grpc/device"
+ "github.com/pomerium/webauthn"
)
// CredentialStorage stores credentials in the databroker.
diff --git a/pkg/webauthnutil/credential_storage_test.go b/pkg/webauthnutil/credential_storage_test.go
index fd776694d..2d3c49df8 100644
--- a/pkg/webauthnutil/credential_storage_test.go
+++ b/pkg/webauthnutil/credential_storage_test.go
@@ -4,13 +4,13 @@ import (
"context"
"testing"
- "github.com/pomerium/webauthn"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/pomerium/pomerium/pkg/grpc/databroker"
+ "github.com/pomerium/webauthn"
)
type mockDataBrokerServiceClient struct {
diff --git a/pkg/webauthnutil/device_type.go b/pkg/webauthnutil/device_type.go
index de66f9dd2..30db8a14a 100644
--- a/pkg/webauthnutil/device_type.go
+++ b/pkg/webauthnutil/device_type.go
@@ -3,7 +3,6 @@ package webauthnutil
import (
"context"
- "github.com/pomerium/webauthn/cose"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
@@ -11,6 +10,7 @@ import (
"github.com/pomerium/pomerium/internal/urlutil"
"github.com/pomerium/pomerium/pkg/grpc/databroker"
"github.com/pomerium/pomerium/pkg/grpc/device"
+ "github.com/pomerium/webauthn/cose"
)
// DefaultDeviceType is the default device type when none is specified.
diff --git a/pkg/webauthnutil/options_test.go b/pkg/webauthnutil/options_test.go
index 91677c4a5..64276750f 100644
--- a/pkg/webauthnutil/options_test.go
+++ b/pkg/webauthnutil/options_test.go
@@ -3,12 +3,12 @@ package webauthnutil
import (
"testing"
- "github.com/pomerium/webauthn"
- "github.com/pomerium/webauthn/cose"
"github.com/stretchr/testify/assert"
"github.com/pomerium/pomerium/pkg/grpc/device"
"github.com/pomerium/pomerium/pkg/grpc/user"
+ "github.com/pomerium/webauthn"
+ "github.com/pomerium/webauthn/cose"
)
func TestGenerateCreationOptions(t *testing.T) {
diff --git a/pkg/webauthnutil/user.go b/pkg/webauthnutil/user.go
index d5e86178c..2c3fe06f6 100644
--- a/pkg/webauthnutil/user.go
+++ b/pkg/webauthnutil/user.go
@@ -2,9 +2,9 @@ package webauthnutil
import (
"github.com/google/uuid"
- "github.com/pomerium/webauthn"
"github.com/pomerium/pomerium/pkg/grpc/user"
+ "github.com/pomerium/webauthn"
)
var pomeriumUserNamespace = uuid.MustParse("2929d3f7-f0b0-478f-9dd5-970d51eb3859")
diff --git a/ui/src/App.tsx b/ui/src/App.tsx
index 5cce3b31d..edd84f9e8 100644
--- a/ui/src/App.tsx
+++ b/ui/src/App.tsx
@@ -2,16 +2,17 @@ import DeviceEnrolledPage from "./components/DeviceEnrolledPage";
import ErrorPage from "./components/ErrorPage";
import Footer from "./components/Footer";
import Header from "./components/Header";
+import SignOutConfirmPage from "./components/SignOutConfirmPage";
+import { ToolbarOffset } from "./components/ToolbarOffset";
import UserInfoPage from "./components/UserInfoPage";
import WebAuthnRegistrationPage from "./components/WebAuthnRegistrationPage";
+import { SubpageContextProvider } from "./context/Subpage";
import { createTheme } from "./theme";
import { PageData } from "./types";
+import Box from "@mui/material/Box";
import CssBaseline from "@mui/material/CssBaseline";
import { ThemeProvider } from "@mui/material/styles";
import React, { FC } from "react";
-import {ToolbarOffset} from "./components/ToolbarOffset";
-import Box from "@mui/material/Box";
-import {SubpageContextProvider} from "./context/Subpage";
const theme = createTheme();
@@ -25,6 +26,9 @@ const App: FC = () => {
case "Error":
body = ;
break;
+ case "SignOutConfirm":
+ body = ;
+ break;
case "UserInfo":
body = ;
break;
@@ -36,15 +40,16 @@ const App: FC = () => {
-
+
-
-
+
+
{body}
diff --git a/ui/src/components/Header.tsx b/ui/src/components/Header.tsx
index 9dd2c2510..05f257bdf 100644
--- a/ui/src/components/Header.tsx
+++ b/ui/src/components/Header.tsx
@@ -1,23 +1,29 @@
+import { PageData } from "../types";
+import { Avatar } from "./Avatar";
import Logo from "./Logo";
+import { ToolbarOffset } from "./ToolbarOffset";
+import UserSidebarContent from "./UserSidebarContent";
+import {
+ Drawer,
+ IconButton,
+ Menu,
+ MenuItem,
+ useMediaQuery,
+} from "@mui/material";
import AppBar from "@mui/material/AppBar";
import Box from "@mui/material/Box";
import Toolbar from "@mui/material/Toolbar";
-import React, {FC, useState} from "react";
-import {useTheme} from "@mui/material/styles";
-import {Drawer, IconButton, Menu, MenuItem, useMediaQuery} from "@mui/material";
-import {ToolbarOffset} from "./ToolbarOffset";
-import UserSidebarContent from "./UserSidebarContent";
-import {ChevronLeft, ChevronRight, Menu as MenuIcon} from "react-feather";
+import { useTheme } from "@mui/material/styles";
import styled from "@mui/material/styles/styled";
-import {Avatar} from "./Avatar";
-import {PageData} from "../types";
-import {get} from 'lodash';
+import { get } from "lodash";
+import React, { FC, useState } from "react";
+import { ChevronLeft, ChevronRight, Menu as MenuIcon } from "react-feather";
-const DrawerHeader = styled('div')(({ theme }) => ({
- display: 'flex',
- alignItems: 'center',
+const DrawerHeader = styled("div")(({ theme }) => ({
+ display: "flex",
+ alignItems: "center",
padding: theme.spacing(0, 1),
- justifyContent: 'flex-end',
+ justifyContent: "flex-end",
}));
type HeaderProps = {
@@ -26,33 +32,34 @@ type HeaderProps = {
};
const Header: FC = ({ includeSidebar, data }) => {
const theme = useTheme();
- const mdUp = useMediaQuery(() => theme.breakpoints.up('md'), {
+ const mdUp = useMediaQuery(() => theme.breakpoints.up("md"), {
defaultMatches: true,
- noSsr: false
+ noSsr: false,
});
const [drawerOpen, setDrawerOpen] = useState(false);
const [anchorEl, setAnchorEl] = React.useState(null);
- const handleMenuOpen = e => {
+ const handleMenuOpen = (e) => {
setAnchorEl(e.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
- const userName = get(data, 'user.name') || get(data, 'user.claims.given_name');
+ const userName =
+ get(data, "user.name") || get(data, "user.claims.given_name");
const handleDrawerOpen = () => {
setDrawerOpen(true);
};
- const handleDrawerClose = ():void => {
+ const handleDrawerClose = (): void => {
setDrawerOpen(false);
};
- const handleLogout = (evt: React.MouseEvent):void => {
+ const handleLogout = (evt: React.MouseEvent): void => {
evt.preventDefault();
location.href = "/.pomerium/sign_out";
- }
+ };
return (
= ({ includeSidebar, data }) => {
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
- sx={{ mr: 2, ...(drawerOpen && { display: 'none' }) }}
+ sx={{ mr: 2, ...(drawerOpen && { display: "none" }) }}
>
@@ -75,11 +82,11 @@ const Header: FC = ({ includeSidebar, data }) => {
sx={{
width: 256,
flexShrink: 0,
- '& .MuiDrawer-paper': {
+ "& .MuiDrawer-paper": {
width: 256,
- boxSizing: 'border-box',
- backgroundColor: 'neutral.900',
- height: '100vh',
+ boxSizing: "border-box",
+ backgroundColor: "neutral.900",
+ height: "100vh",
},
}}
variant="persistent"
@@ -88,10 +95,14 @@ const Header: FC = ({ includeSidebar, data }) => {
>
- {theme.direction === 'ltr' ? : }
+ {theme.direction === "ltr" ? (
+
+ ) : (
+
+ )}
-
+
>
@@ -104,13 +115,16 @@ const Header: FC = ({ includeSidebar, data }) => {
{userName && (
<>
-
+