-
Notifications
You must be signed in to change notification settings - Fork 0
132 security dialog #155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
132 security dialog #155
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,3 +1,188 @@ | ||||||
| import React, { useState } from 'react'; | ||||||
| import { createAuthClient } from 'better-auth/client'; | ||||||
| import { Button } from '@/components/ui/button'; | ||||||
| import { Input } from '@/components/ui/input'; | ||||||
| import { Label } from '@/components/ui/label'; | ||||||
| import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; | ||||||
| import { Separator } from '@/components/ui/separator'; | ||||||
| import { AlertCircle, LogOut, Shield, Lock } from 'lucide-react'; | ||||||
| import { Alert, AlertDescription } from '@/components/ui/alert'; | ||||||
| import { forceLogout } from "@/lib/auth/logout"; | ||||||
|
|
||||||
|
|
||||||
| export function SecuritySettingsContent() { | ||||||
| return <>Security coming soon...</>; | ||||||
| } | ||||||
| const [currentPassword, setCurrentPassword] = useState(''); | ||||||
| const [newPassword, setNewPassword] = useState(''); | ||||||
| const [confirmPassword, setConfirmPassword] = useState(''); | ||||||
| const [loading, setLoading] = useState(false); | ||||||
| const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null); | ||||||
|
|
||||||
| const authClient = createAuthClient() | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Creates a new auth client instance on every render. Move outside component or memoize.
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/components/settings/pages/security-settings-content.tsx
Line: 20:20
Comment:
Creates a new auth client instance on every render. Move outside component or memoize.
```suggestion
const authClient = React.useMemo(() => createAuthClient(), []);
```
How can I resolve this? If you propose a fix, please make it concise.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah this is really important, you should just import it from where greptile mentioned |
||||||
|
|
||||||
| const handleLogout = async () => { | ||||||
| await forceLogout(); | ||||||
| }; | ||||||
|
|
||||||
| const handleRevokeAllSessions = async () => { | ||||||
| try { | ||||||
| setLoading(true); | ||||||
| await authClient.revokeOtherSessions(); | ||||||
| setMessage({ type: 'success', text: 'All other sessions have been revoked' }); | ||||||
| } catch (error) { | ||||||
| setMessage({ type: 'error', text: 'Failed to revoke sessions. Please try again.' }); | ||||||
| } finally { | ||||||
| setLoading(false); | ||||||
| } | ||||||
| }; | ||||||
|
|
||||||
| const handleChangePassword = async () => { | ||||||
| setMessage(null); | ||||||
|
|
||||||
| if (newPassword !== confirmPassword) { | ||||||
| setMessage({ type: 'error', text: 'New passwords do not match' }); | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| if (newPassword.length < 8) { | ||||||
| setMessage({ type: 'error', text: 'Password must be at least 8 characters long' }); | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| try { | ||||||
| setLoading(true); | ||||||
| await authClient.changePassword({ | ||||||
| currentPassword, | ||||||
| newPassword, | ||||||
| revokeOtherSessions: false, | ||||||
| }); | ||||||
| setMessage({ type: 'success', text: 'Password changed successfully' }); | ||||||
| setCurrentPassword(''); | ||||||
| setNewPassword(''); | ||||||
| setConfirmPassword(''); | ||||||
| } catch (error) { | ||||||
| setMessage({ type: 'error', text: 'Failed to change password. Please check your current password.' }); | ||||||
| } finally { | ||||||
| setLoading(false); | ||||||
| } | ||||||
| }; | ||||||
|
|
||||||
| return ( | ||||||
| <div className="space-y-6 max-h-[calc(100vh-200px)] overflow-y-auto px-1"> | ||||||
| <div> | ||||||
| <h3 className="text-lg font-medium">Security</h3> | ||||||
| <p className="text-sm text-muted-foreground"> | ||||||
| Manage your account security and sessions | ||||||
| </p> | ||||||
| </div> | ||||||
| <Separator /> | ||||||
|
|
||||||
| {message && ( | ||||||
| <Alert variant={message.type === 'error' ? 'destructive' : 'default'}> | ||||||
| <AlertCircle className="h-4 w-4" /> | ||||||
| <AlertDescription>{message.text}</AlertDescription> | ||||||
| </Alert> | ||||||
| )} | ||||||
|
|
||||||
| <Card> | ||||||
| <CardHeader> | ||||||
| <CardTitle className="flex items-center gap-2"> | ||||||
| <Lock className="h-5 w-5" /> | ||||||
| Change Password | ||||||
| </CardTitle> | ||||||
| <CardDescription> | ||||||
| Update your password to keep your account secure | ||||||
| </CardDescription> | ||||||
| </CardHeader> | ||||||
| <CardContent> | ||||||
| <div className="space-y-4"> | ||||||
| <div className="space-y-2"> | ||||||
| <Label htmlFor="current-password">Current Password</Label> | ||||||
| <Input | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have a way to do forms that isn't manual. See the login and signup pages for examples. |
||||||
| id="current-password" | ||||||
| type="password" | ||||||
| value={currentPassword} | ||||||
| onChange={(e) => setCurrentPassword(e.target.value)} | ||||||
| disabled={loading} | ||||||
| /> | ||||||
| </div> | ||||||
| <div className="space-y-2"> | ||||||
| <Label htmlFor="new-password">New Password</Label> | ||||||
| <Input | ||||||
| id="new-password" | ||||||
| type="password" | ||||||
| value={newPassword} | ||||||
| onChange={(e) => setNewPassword(e.target.value)} | ||||||
| disabled={loading} | ||||||
| /> | ||||||
| </div> | ||||||
| <div className="space-y-2"> | ||||||
| <Label htmlFor="confirm-password">Confirm New Password</Label> | ||||||
| <Input | ||||||
| id="confirm-password" | ||||||
| type="password" | ||||||
| value={confirmPassword} | ||||||
| onChange={(e) => setConfirmPassword(e.target.value)} | ||||||
| disabled={loading} | ||||||
| /> | ||||||
| </div> | ||||||
| <Button onClick={handleChangePassword} disabled={loading}> | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Button is not disabled when required fields are empty. Users can submit with empty passwords.
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/components/settings/pages/security-settings-content.tsx
Line: 128:128
Comment:
Button is not disabled when required fields are empty. Users can submit with empty passwords.
```suggestion
<Button onClick={handleChangePassword} disabled={loading || !currentPassword || !newPassword || !confirmPassword}>
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||
| {loading ? 'Updating...' : 'Update Password'} | ||||||
| </Button> | ||||||
| </div> | ||||||
| </CardContent> | ||||||
| </Card> | ||||||
|
|
||||||
| <Card> | ||||||
| <CardHeader> | ||||||
| <CardTitle className="flex items-center gap-2"> | ||||||
| <Shield className="h-5 w-5" /> | ||||||
| Session Management | ||||||
| </CardTitle> | ||||||
| <CardDescription> | ||||||
| Manage your active sessions across all devices | ||||||
| </CardDescription> | ||||||
| </CardHeader> | ||||||
| <CardContent className="space-y-4"> | ||||||
| <div className="flex items-center justify-between"> | ||||||
| <div className="space-y-0.5"> | ||||||
| <p className="text-sm font-medium">Logout from all devices</p> | ||||||
| <p className="text-sm text-muted-foreground"> | ||||||
| End all sessions except the current one | ||||||
| </p> | ||||||
| </div> | ||||||
| <Button | ||||||
| variant="outline" | ||||||
| onClick={handleRevokeAllSessions} | ||||||
| disabled={loading} | ||||||
| > | ||||||
| Revoke All Sessions | ||||||
| </Button> | ||||||
| </div> | ||||||
| </CardContent> | ||||||
| </Card> | ||||||
|
|
||||||
| <Card> | ||||||
| <CardHeader> | ||||||
| <CardTitle className="flex items-center gap-2"> | ||||||
| <LogOut className="h-5 w-5" /> | ||||||
| Logout | ||||||
| </CardTitle> | ||||||
| <CardDescription> | ||||||
| Sign out of your account on this device | ||||||
| </CardDescription> | ||||||
| </CardHeader> | ||||||
| <CardContent> | ||||||
| <Button | ||||||
| variant="destructive" | ||||||
| onClick={handleLogout} | ||||||
| disabled={loading} | ||||||
| className="w-full sm:w-auto" | ||||||
| > | ||||||
| <LogOut className="mr-2 h-4 w-4" /> | ||||||
| Logout | ||||||
| </Button> | ||||||
| </CardContent> | ||||||
| </Card> | ||||||
| </div> | ||||||
| ); | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Importing from
better-auth/clientbut existing codebase usesbetter-auth/react(seesrc/lib/auth/client.ts:3). Use the sharedauthClientfrom@/lib/auth/clientinstead of creating a new instance.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI