Compare commits

...

2 Commits

Author SHA1 Message Date
hyung-hwan d500c611dd updated Topbar to show the display name if not blank.
changed to use the display name as part of TOTP provisioning URL if not blank
2026-06-10 21:54:22 +09:00
hyung-hwan e6667f2e9d updated AccountPage to navigate to / upon successful TOTP verification 2026-06-10 21:28:01 +09:00
5 changed files with 14 additions and 4 deletions
+1
View File
@@ -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
+7 -2
View File
@@ -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})
} }
+1 -1
View File
@@ -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}
+1 -1
View File
@@ -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
View File
@@ -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)