Skip to content

Commit

Permalink
[SOA-39] Enable CSRF (#58)
Browse files Browse the repository at this point in the history
* chore 🏗️ : added axios for automatic CSRF_token extraction

* refactor ✨ (fe): update client request to use axios

* fix ✅ : correction to userfollow target
  • Loading branch information
mariadriana-deemaze authored Dec 10, 2024
1 parent 05762bc commit c9e00a6
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 55 deletions.
4 changes: 2 additions & 2 deletions app/controllers/user_follows_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export default class UserFollowsController {
const currentUserId = ctx.auth.user?.id!
const followerId = ctx.params.userId
try {
await this.service.destroy(currentUserId, followerId)
return ctx.response.status(200)
await this.service.destroy(followerId, currentUserId)
return ctx.response.noContent()
} catch (error) {
logger.error(error)
return ctx.session.flash('errors', { message: 'Error occurred.' })
Expand Down
8 changes: 4 additions & 4 deletions app/services/user_follow_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export default class UserFollowService {
return result.count
}

async show(currentUserId: UUID, followerUserId: UUID): Promise<UserFollower | null> {
async show(targetId: UUID, followerUserId: UUID): Promise<UserFollower | null> {
const [relation] = await UserFollower.query()
.where('user_id', currentUserId)
.where('user_id', targetId)
.andWhere('follower_id', followerUserId)
.limit(1)
return relation
Expand All @@ -31,8 +31,8 @@ export default class UserFollowService {
return relation
}

async destroy(currentUserId: UUID, followerUserId: UUID) {
const relation = await this.show(currentUserId, followerUserId)
async destroy(targetId: UUID, followerUserId: UUID) {
const relation = await this.show(targetId, followerUserId)
if (!relation) return null
await relation.delete()
}
Expand Down
5 changes: 2 additions & 3 deletions config/shield.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ const shieldConfig = defineConfig({
* to learn more
*/
csrf: {
// enabled: true,
enabled: false,
enabled: true,
exceptRoutes: [],
// enableXsrfCookie: true,
enableXsrfCookie: true,
methods: ['POST', 'PUT', 'PATCH', 'DELETE'],
},

Expand Down
8 changes: 4 additions & 4 deletions inertia/components/posts/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { UserResponse } from '#interfaces/user'
import HighlightedInput from '@/components/generic/highlighted_input'
import { UserAvatar } from '@/components/generic/user_avatar'
import { REGEX, replaceLast } from '#utils/index'
import axios from 'axios'

const MAX_FILES = 3

Expand Down Expand Up @@ -52,17 +53,16 @@ export default function Form({
const method = post ? 'patch' : 'post'

async function handleFetch(searchTerm: string) {
const request = await fetch(
const request = await axios.get(
route('users.index', {
qs: {
search: searchTerm,
},
}).path
)

if (request.ok) {
const json = await request.json()
return json.data
if (request.status === 200) {
return request.data.data
}

return []
Expand Down
21 changes: 8 additions & 13 deletions inertia/components/posts/post_card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { UserResponse } from '#interfaces/user'
import { route } from '@izzyjs/route/client'
import { useToast } from '@/components/ui/use_toast'
import { cn } from '@/lib/utils'
import axios from 'axios'

type PostActions = 'update' | 'delete' | 'report' | 'pin'

Expand Down Expand Up @@ -246,17 +247,14 @@ function PostReaction({

const isDelete = react === reaction.type

const request = await fetch(
const request = await axios(
route('posts_reactions.store', { params: { id: post?.id! } }).path,
{
method: isDelete ? 'delete' : 'post',
headers: {
'content-type': 'application/json',
},
...(!isDelete && {
body: JSON.stringify({
data: {
reaction: react,
}),
},
}),
}
)
Expand Down Expand Up @@ -358,27 +356,24 @@ function PostActions({
const { toast } = useToast()

async function updatePin() {
const request = await fetch(
const request = await axios(
route('posts_pins.update', {
params: {
id: post.id,
},
}).path,
{
method: 'post',
headers: {
'content-type': 'application/json',
},
}
)

if (request.ok) {
const { pinned } = await request.json()
if (request.status === 200) {
const { pinned } = await request.data
setPostState((prevState) => {
return { ...prevState, pinned }
})
} else {
const { message } = await request.json()
const { message } = await request.data
toast({ title: 'Unable to pin post', description: message })
}
}
Expand Down
21 changes: 6 additions & 15 deletions inertia/components/posts/report.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
import { PostReportReason } from '#enums/post'
import { Send } from 'lucide-react'
import { route } from '@izzyjs/route/client'
import axios from 'axios'

export function ReportPost({ post, trigger }: { post: PostResponse; trigger: ReactNode }) {
const [open, setOpen] = useState(false)
Expand All @@ -44,16 +45,9 @@ export function ReportPost({ post, trigger }: { post: PostResponse; trigger: Rea
const { toast } = useToast()

async function getUserPostReport() {
fetch(route('posts_reports.show', { params: { id: post.id } }).path, {
method: 'get',
headers: {
'content-type': 'application/json',
},
})
.then((response) => {
return response.json()
})
.then((json) => {
axios
.get(route('posts_reports.show', { params: { id: post.id } }).path)
.then(({ data: json }) => {
if (json) {
setHasReported({
id: json.id,
Expand All @@ -76,12 +70,9 @@ export function ReportPost({ post, trigger }: { post: PostResponse; trigger: Rea

e.preventDefault()
setIsSubmitting(true)
fetch(url, {
axios(url, {
method,
headers: {
'content-type': 'application/json',
},
body: JSON.stringify(data),
data,
})
.then(() => {
setSubmitted(true)
Expand Down
11 changes: 6 additions & 5 deletions inertia/components/users/_notifications_dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { BadgeInfo, BellDot, CheckCheck, Clock, Loader2 } from 'lucide-react'
import { NotificationType } from '#enums/notification'
import { PostReactionType } from '#enums/post'
import { formatDistanceToNow } from 'date-fns'
import axios from 'axios'

export default function NotificationsDropdown() {
const [notificationsLoadState, setNotificationsLoadState] = useState<
Expand All @@ -31,9 +32,9 @@ export default function NotificationsDropdown() {
]

async function getUserNotifications() {
const request = await fetch(route('notifications.index').path, { method: 'GET' })
if (request.ok) {
const data: NotificationResponse[] = await request.json()
const request = await axios.get(route('notifications.index').path)
if (request.status === 200) {
const data: NotificationResponse[] = request.data
if (data.length !== notifications.length) {
setNotifications(data)
setNotificationsLoadState('loaded')
Expand All @@ -44,8 +45,8 @@ export default function NotificationsDropdown() {
}

async function markAllAsRead() {
const request = await fetch(route('notifications.update').path, { method: 'POST' })
if (request.ok) {
const request = await axios.post(route('notifications.update').path)
if (request.status === 200) {
setNotifications([])
setMarkedAsRead(true)
}
Expand Down
15 changes: 6 additions & 9 deletions inertia/pages/users/show.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { route } from '@izzyjs/route/client'
import { UserAvatar } from '@/components/generic/user_avatar'
import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import axios from 'axios'

function UserCard({
currentUser,
Expand All @@ -36,18 +37,14 @@ function UserCard({
}).path

if (follow === 'following') {
fetch(url, {
method: 'delete',
}).then(() => {
axios.delete(url).then(() => {
setFollow('not-following')
setProfileData((prevState) => {
return { ...prevState, followersCount: +prevState.followersCount - 1 }
})
})
} else {
fetch(url, {
method: 'post',
}).then(() => {
axios.post(url).then(() => {
setFollow('following')
setProfileData((prevState) => {
return { ...prevState, followersCount: +prevState.followersCount + 1 }
Expand Down Expand Up @@ -134,16 +131,16 @@ export default function Show({ user, posts, profile }: InferPageProps<FeedContro

async function followStatus() {
if (!profile) return
const request = await fetch(
const request = await axios.get(
route('users_follows.show', {
params: {
userId: profile.id,
},
}).path
)

if (request.ok) {
const json: { following: boolean } = await request.json()
if (request.status === 200) {
const json: { following: boolean } = await request.data
if (json.following) {
setFollow('following')
} else {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"@typescript-eslint/eslint-plugin": "^7.15.0",
"@vinejs/vine": "^2.1.0",
"autoprefixer": "^10.4.19",
"axios": "^1.7.9",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cmdk": "^1.0.4",
Expand Down
9 changes: 9 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4355,6 +4355,15 @@ axios@^1.6.0:
form-data "^4.0.0"
proxy-from-env "^1.1.0"

axios@^1.7.9:
version "1.7.9"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a"
integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==
dependencies:
follow-redirects "^1.15.6"
form-data "^4.0.0"
proxy-from-env "^1.1.0"

balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
Expand Down

0 comments on commit c9e00a6

Please sign in to comment.