Skip to content

Commit 7a99119

Browse files
authored
Merge pull request #18 from whythawk/fix-login-artifacts
Fixed login artifacts
2 parents ff11270 + 132f847 commit 7a99119

File tree

7 files changed

+16
-157
lines changed

7 files changed

+16
-157
lines changed

{{cookiecutter.project_slug}}/backend/app/app/api/api_v1/endpoints/login.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from typing import Any, Union, Dict
2+
from pydantic import EmailStr
23

34
from fastapi import APIRouter, Body, Depends, HTTPException
45
from fastapi.security import OAuth2PasswordRequestForm
@@ -33,14 +34,14 @@
3334

3435

3536
@router.post("/magic/{email}", response_model=schemas.WebToken)
36-
def login_with_magic_link(*, db: Session = Depends(deps.get_db), email: str) -> Any:
37+
def login_with_magic_link(*, db: Session = Depends(deps.get_db), email: EmailStr) -> Any:
3738
"""
3839
First step of a 'magic link' login. Check if the user exists and generate a magic link. Generates two short-duration
3940
jwt tokens, one for validation, one for email. Creates user if not exist.
4041
"""
4142
user = crud.user.get_by_email(db, email=email)
4243
if not user:
43-
user_in = schemas.UserCreate(**{email: email})
44+
user_in = schemas.UserCreate(**{"email": email})
4445
user = crud.user.create(db, obj_in=user_in)
4546
if not crud.user.is_active(user):
4647
# Still permits a timed-attack, but does create ambiguity.

{{cookiecutter.project_slug}}/backend/app/app/api/api_v1/endpoints/users.py

-43
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from app.core.config import settings
1111
from app.core import security
1212
from app.utilities import (
13-
send_email_validation_email,
1413
send_new_account_email,
1514
)
1615

@@ -111,48 +110,6 @@ def request_new_totp(
111110
return obj_in
112111

113112

114-
# @router.post("/send-validation-email", response_model=schemas.Msg, status_code=201)
115-
# def send_validation_email(
116-
# *,
117-
# current_user: models.User = Depends(deps.get_current_active_user),
118-
# ) -> Any:
119-
# """
120-
# Send validation email.
121-
# """
122-
# password_validation_token = generate_password_reset_token(email=current_user.email)
123-
# data = schemas.EmailValidation(
124-
# **{
125-
# "email": current_user.email,
126-
# "subject": "Validate your email address",
127-
# "token": password_validation_token,
128-
# }
129-
# )
130-
# # EmailValidation
131-
# send_email_validation_email(data=data)
132-
# return {"msg": "Password validation email sent. Check your email and respond."}
133-
134-
135-
@router.post("/validate-email", response_model=schemas.Msg)
136-
def validate_email(
137-
*,
138-
db: Session = Depends(deps.get_db),
139-
payload: dict = Body(...),
140-
current_user: models.User = Depends(deps.get_current_active_user),
141-
) -> Any:
142-
"""
143-
Reset password
144-
"""
145-
# https://stackoverflow.com/a/65114346/295606
146-
email = verify_password_reset_token(payload["validation"])
147-
if not email or current_user.email != email:
148-
raise HTTPException(
149-
status_code=400,
150-
detail="Invalid token",
151-
)
152-
crud.user.validate_email(db=db, db_obj=current_user)
153-
return {"msg": "Email address validated successfully."}
154-
155-
156113
@router.post("/toggle-state", response_model=schemas.Msg)
157114
def toggle_state(
158115
*,

{{cookiecutter.project_slug}}/backend/app/app/crud/crud_user.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ def get_by_email(self, db: Session, *, email: str) -> Optional[User]:
1616
def create(self, db: Session, *, obj_in: UserCreate) -> User:
1717
db_obj = User(
1818
email=obj_in.email,
19-
hashed_password=get_password_hash(obj_in.password),
2019
full_name=obj_in.full_name,
2120
is_superuser=obj_in.is_superuser,
2221
)
22+
if obj_in.password:
23+
db_obj.hashed_password = get_password_hash(obj_in.password)
2324
db.add(db_obj)
2425
db.commit()
2526
db.refresh(db_obj)

{{cookiecutter.project_slug}}/frontend/api/auth.ts

-17
Original file line numberDiff line numberDiff line change
@@ -146,23 +146,6 @@ export const apiAuth = {
146146
}
147147
)
148148
},
149-
async requestValidationEmail(token: string) {
150-
return await useFetch<IMsg>(`${apiCore.url()}/users/send-validation-email`,
151-
{
152-
method: "POST",
153-
headers: apiCore.headers(token)
154-
}
155-
)
156-
},
157-
async validateEmail(token: string, validation: string) {
158-
return await useFetch<IMsg>(`${apiCore.url()}/users/validate-email`,
159-
{
160-
method: "POST",
161-
body: { validation },
162-
headers: apiCore.headers(token)
163-
}
164-
)
165-
},
166149
// ADMIN USER MANAGEMENT
167150
async getAllUsers(token: string) {
168151
return await useFetch<IUserProfile[]>(`${apiCore.url()}/users/all`,

{{cookiecutter.project_slug}}/frontend/components/settings/ValidateEmailButton.vue

-25
This file was deleted.

{{cookiecutter.project_slug}}/frontend/pages/settings.vue

+11-23
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,22 @@
44
<div class="lg:grid lg:grid-cols-12 lg:gap-x-5">
55
<aside class="py-6 px-2 sm:px-6 lg:col-span-3 lg:py-0 lg:px-0">
66
<nav class="space-y-1" aria-label="tabs">
7-
<button
8-
v-for="item in navigation"
9-
:key="`settings-${item.id}`"
10-
:class="[item.id === selected
11-
? 'text-rose-700 hover:text-rose-700'
12-
: 'text-gray-900 hover:text-gray-900', 'group rounded-md px-3 py-2 flex items-center text-sm font-medium']"
13-
@click.prevent="changeSelection(item.id)"
14-
>
15-
<component
16-
:is="item.icon"
17-
:class="[item.id === selected
18-
? 'text-rose-700 group-hover:text-rose-700'
19-
: 'text-gray-400 group-hover:text-gray-500', 'flex-shrink-0 -ml-1 mr-3 h-6 w-6']" aria-hidden="true"
20-
/>
7+
<button v-for="item in navigation" :key="`settings-${item.id}`"
8+
:class="[item.id === selected
9+
? 'text-ochre-700 hover:text-ochre-700'
10+
: 'text-gray-900 hover:text-gray-900', 'group rounded-md px-3 py-2 flex items-center text-sm font-medium']" @click.prevent="changeSelection(item.id)">
11+
<component :is="item.icon" :class="[item.id === selected
12+
? 'text-ochre-700 group-hover:text-ochre-700'
13+
: 'text-gray-400 group-hover:text-gray-500', 'flex-shrink-0 -ml-1 mr-3 h-6 w-6']" aria-hidden="true" />
2114
<span class="truncate">{{ item.name }}</span>
2215
</button>
23-
<button
24-
v-if="auth.is_superuser"
16+
<button v-if="auth.is_superuser"
2517
class="text-gray-900 hover:text-gray-900 group rounded-md px-3 py-2 flex items-center text-sm font-medium cursor-pointer"
26-
@click.prevent="navigateTo('/moderation')"
27-
>
28-
<component
29-
:is="UsersIcon"
30-
class="text-gray-400 group-hover:text-gray-500 flex-shrink-0 -ml-1 mr-3 h-6 w-6" aria-hidden="true"
31-
/>
18+
@click.prevent="navigateTo('/moderation')">
19+
<component :is="UsersIcon" class="text-gray-400 group-hover:text-gray-500 flex-shrink-0 -ml-1 mr-3 h-6 w-6"
20+
aria-hidden="true" />
3221
<span class="truncate">Moderation</span>
3322
</button>
34-
<SettingsValidateEmailButton v-if="!auth.profile.email_validated"/>
3523
</nav>
3624
</aside>
3725
<div class="space-y-6 ml-3 sm:px-6 lg:col-span-9 min-w-full lg:px-0">

{{cookiecutter.project_slug}}/frontend/stores/auth.ts

-46
Original file line numberDiff line numberDiff line change
@@ -191,52 +191,6 @@ export const useAuthStore = defineStore("authUser", {
191191
this.password = payload.password
192192
this.totp = payload.totp
193193
},
194-
async sendEmailValidation() {
195-
await this.authTokens.refreshTokens()
196-
if (this.authTokens.token && !this.email_validated) {
197-
try {
198-
const { data: response } = await apiAuth.requestValidationEmail(this.authTokens.token)
199-
if (response.value) {
200-
toasts.addNotice({
201-
title: "Validation sent",
202-
content: response.value.msg,
203-
})
204-
}
205-
} catch (error) {
206-
toasts.addNotice({
207-
title: "Validation error",
208-
content: "Please check your email and try again.",
209-
icon: "error"
210-
})
211-
}
212-
}
213-
},
214-
async validateEmail(validationToken: string) {
215-
await this.authTokens.refreshTokens()
216-
if (this.authTokens.token && !this.email_validated) {
217-
try {
218-
const { data: response } = await apiAuth.validateEmail(
219-
this.authTokens.token,
220-
validationToken
221-
)
222-
if (response.value) {
223-
this.email_validated = true
224-
if (response.value) {
225-
toasts.addNotice({
226-
title: "Success",
227-
content: response.value.msg,
228-
})
229-
}
230-
}
231-
} catch (error) {
232-
toasts.addNotice({
233-
title: "Validation error",
234-
content: "Invalid token. Check your email and resend validation.",
235-
icon: "error"
236-
})
237-
}
238-
}
239-
},
240194
async recoverPassword(email: string) {
241195
if (!this.loggedIn) {
242196
try {

0 commit comments

Comments
 (0)