Compare commits
2 Commits
8e9befe184
...
d500c611dd
| Author | SHA1 | Date | |
|---|---|---|---|
| d500c611dd | |||
| e6667f2e9d |
@@ -350,6 +350,7 @@ func (api *API) oidcGetOrCreateUser(ctx context.Context, claims oidcUserClaims)
|
|||||||
var hash string
|
var hash string
|
||||||
var err error
|
var err error
|
||||||
var created models.User
|
var created models.User
|
||||||
|
|
||||||
username = oidcUsernameFromSub(claims.Sub)
|
username = oidcUsernameFromSub(claims.Sub)
|
||||||
user, hash, err = api.storeContext(ctx).GetUserByUsername(username)
|
user, hash, err = api.storeContext(ctx).GetUserByUsername(username)
|
||||||
_ = hash
|
_ = hash
|
||||||
|
|||||||
@@ -114,11 +114,13 @@ func (api *API) GetMyTOTP(w http.ResponseWriter, r *http.Request, _ map[string]s
|
|||||||
|
|
||||||
func (api *API) SetupMyTOTP(w http.ResponseWriter, r *http.Request, _ map[string]string) {
|
func (api *API) SetupMyTOTP(w http.ResponseWriter, r *http.Request, _ map[string]string) {
|
||||||
var ctxUser models.User
|
var ctxUser models.User
|
||||||
var ok bool
|
|
||||||
var secret string
|
var secret string
|
||||||
var encrypted string
|
var encrypted string
|
||||||
var url string
|
var url string
|
||||||
|
var displayName string
|
||||||
|
var ok bool
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
ctxUser, ok = middleware.UserFromContext(r.Context())
|
ctxUser, ok = middleware.UserFromContext(r.Context())
|
||||||
if !ok {
|
if !ok {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
@@ -139,7 +141,10 @@ func (api *API) SetupMyTOTP(w http.ResponseWriter, r *http.Request, _ map[string
|
|||||||
WriteJSONWithErrorReason(w, r, http.StatusInternalServerError, err.Error())
|
WriteJSONWithErrorReason(w, r, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
url = auth.TOTPProvisioningURL(api.totpIssuer(r), ctxUser.Username, secret)
|
|
||||||
|
displayName = ctxUser.DisplayName
|
||||||
|
if displayName == "" { displayName = ctxUser.Username }
|
||||||
|
url = auth.TOTPProvisioningURL(api.totpIssuer(r), displayName, secret)
|
||||||
WriteJSON(w, http.StatusOK, totpSetupResponse{Secret: secret, OTPAuthURL: url})
|
WriteJSON(w, http.StatusOK, totpSetupResponse{Secret: secret, OTPAuthURL: url})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ export default function Layout() {
|
|||||||
{user ? (
|
{user ? (
|
||||||
<>
|
<>
|
||||||
<Button color="inherit" onClick={openAccountMenu} endIcon={<KeyboardArrowDownIcon />}>
|
<Button color="inherit" onClick={openAccountMenu} endIcon={<KeyboardArrowDownIcon />}>
|
||||||
{user.username}
|
{user.display_name || user.username}
|
||||||
</Button>
|
</Button>
|
||||||
<Menu
|
<Menu
|
||||||
anchorEl={accountMenuAnchor}
|
anchorEl={accountMenuAnchor}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import App from './app/App'
|
|||||||
import { routes } from './app/routes'
|
import { routes } from './app/routes'
|
||||||
|
|
||||||
const router = createBrowserRouter(routes, {
|
const router = createBrowserRouter(routes, {
|
||||||
future: { v7_startTransition: true, v7_relativeSplatPath: true }
|
future: { v7_relativeSplatPath: true }
|
||||||
})
|
})
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import { Box, Button, Paper, TextField, Typography } from '@mui/material'
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { QRCodeSVG } from 'qrcode.react'
|
import { QRCodeSVG } from 'qrcode.react'
|
||||||
import { api, TOTPSetupResponse, User } from '../api'
|
import { api, TOTPSetupResponse, User } from '../api'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
export default function AccountPage() {
|
export default function AccountPage() {
|
||||||
|
const navigate = useNavigate()
|
||||||
const [user, setUser] = useState<User | null>(null)
|
const [user, setUser] = useState<User | null>(null)
|
||||||
const [displayName, setDisplayName] = useState('')
|
const [displayName, setDisplayName] = useState('')
|
||||||
const [email, setEmail] = useState('')
|
const [email, setEmail] = useState('')
|
||||||
@@ -118,12 +120,14 @@ export default function AccountPage() {
|
|||||||
|
|
||||||
const handleVerifyTOTP = async () => {
|
const handleVerifyTOTP = async () => {
|
||||||
let message: string
|
let message: string
|
||||||
|
|
||||||
setTOTPBusy(true)
|
setTOTPBusy(true)
|
||||||
setTOTPError(null)
|
setTOTPError(null)
|
||||||
try {
|
try {
|
||||||
await api.verifyMyTOTP(totpCode.trim())
|
await api.verifyMyTOTP(totpCode.trim())
|
||||||
setTOTPVerifyRequired(false)
|
setTOTPVerifyRequired(false)
|
||||||
setTOTPCode('')
|
setTOTPCode('')
|
||||||
|
navigate('/') // LoginPage.tsx also navigates to '/'.
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
message = err instanceof Error ? err.message : 'Failed to verify TOTP'
|
message = err instanceof Error ? err.message : 'Failed to verify TOTP'
|
||||||
setTOTPError(message)
|
setTOTPError(message)
|
||||||
|
|||||||
Reference in New Issue
Block a user