Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions apps/docs/spec/supabase_dart_v2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1633,9 +1633,9 @@ functions:
notes: |
This section contains methods commonly used for Multi-Factor Authentication (MFA) and are invoked behind the `supabase.auth.mfa` namespace.

Currently, we only support time-based one-time password (TOTP) as the 2nd factor. We don't support recovery codes but we allow users to enroll more than 1 TOTP factor, with an upper limit of 10.
Currently, Supabase supports time-based one-time password (TOTP) and phone verification code as the 2nd factor. Recovery codes are not supported but users can enroll multiple factors, with an upper limit of 10..

Having a 2nd TOTP factor for recovery means the user doesn't have to store their recovery codes. It also reduces the attack surface since the recovery factor is usually time-limited and not a single static code.
Having a 2nd factor for recovery frees the user of the burden of having to store their recovery codes somewhere. It also reduces the attack surface since multiple recovery codes are usually generated compared to just having 1 backup factor.

Learn more about implementing MFA on your application on our guide [here](https://supabase.com/docs/guides/auth/auth-mfa#overview).
- id: mfa-enroll
Expand All @@ -1644,7 +1644,7 @@ functions:
Starts the enrollment process for a new Multi-Factor Authentication (MFA) factor. This method creates a new `unverified` factor.
To verify a factor, present the QR code or secret to the user and ask them to add it to their authenticator app.
The user has to enter the code from their authenticator app to verify it.
- Currently, `totp` is the only supported `factorType`. The returned `id` should be used to create a challenge.
- Use `totp` or `phone` as the `factorType` and the returned `id` to create a challenge.
- To create a challenge, see [`mfa.challenge()`](/docs/reference/dart/auth-mfa-challenge).
- To verify a challenge, see [`mfa.verify()`](/docs/reference/dart/auth-mfa-verify).
- To create and verify a challenge in a single step, see [`mfa.challengeAndVerify()`](/docs/reference/dart/auth-mfa-challengeandverify).
Expand All @@ -1661,6 +1661,10 @@ functions:
isOptional: true
type: String
description: Human readable name assigned to the factor.
- name: phone
isOptional: true
type: String
description: Phone number to enroll for phone factor type.
examples:
- id: enroll-totp-factor
name: Enroll a time-based, one-time password (TOTP) factor
Expand All @@ -1681,6 +1685,27 @@ functions:
secret: '<SECRET>',
uri: '<URI>',
),
phone: null,
);
```
- id: enroll-phone-factor
name: Enroll a Phone Factor
isSpotlight: true
code: |
```dart
final res = await supabase.auth.mfa.enroll(factorType: FactorType.phone, phone: '+1234567890');

final phone = res.phone;
```
response: |
```json
AuthMFAEnrollResponse(
id: '<ID>',
type: FactorType.phone,
totp: null,
phone: PhoneEnrollment(
phone: '+1234567890',
),
);
```
- id: mfa-challenge
Expand Down
2 changes: 2 additions & 0 deletions apps/docs/spec/supabase_js_v2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2128,6 +2128,8 @@ functions:
Currently, there is support for time-based one-time password (TOTP) and phone verification code as the 2nd factor. Recovery codes are not supported but users can enroll multiple factors, with an upper limit of 10.

Having a 2nd factor for recovery frees the user of the burden of having to store their recovery codes somewhere. It also reduces the attack surface since multiple recovery codes are usually generated compared to just having 1 backup factor.

Learn more about implementing MFA in your application [in the MFA guide](https://supabase.com/docs/guides/auth/auth-mfa#overview).
- id: mfa-enroll
title: 'mfa.enroll()'
$ref: '@supabase/auth-js.GoTrueMFAApi.enroll'
Expand Down
36 changes: 19 additions & 17 deletions apps/studio/components/interfaces/Storage/BucketRow.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { useState } from 'react'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { noop } from 'lodash'
import { Columns3, Edit2, MoreVertical, Trash, XCircle } from 'lucide-react'
import Link from 'next/link'

import type { Bucket } from 'data/storage/buckets-query'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import EditBucketModal from 'components/interfaces/Storage/EditBucketModal'
import DeleteBucketModal from 'components/interfaces/Storage/DeleteBucketModal'
import EmptyBucketModal from 'components/interfaces/Storage/EmptyBucketModal'
import {
Badge,
Button,
Expand All @@ -23,20 +26,15 @@ export interface BucketRowProps {
bucket: Bucket
projectRef?: string
isSelected: boolean
onSelectEmptyBucket: () => void
onSelectDeleteBucket: () => void
onSelectEditBucket: () => void
}

const BucketRow = ({
bucket,
projectRef = '',
isSelected = false,
onSelectEmptyBucket = noop,
onSelectDeleteBucket = noop,
onSelectEditBucket = noop,
}: BucketRowProps) => {
const canUpdateBuckets = useCheckPermissions(PermissionAction.STORAGE_WRITE, '*')
const BucketRow = ({ bucket, projectRef = '', isSelected = false }: BucketRowProps) => {
const { can: canUpdateBuckets } = useAsyncCheckProjectPermissions(
PermissionAction.STORAGE_WRITE,
'*'
)
const [modal, setModal] = useState<string | null>(null)
const onClose = () => setModal(null)

return (
<div
Expand Down Expand Up @@ -84,7 +82,7 @@ const BucketRow = ({
<DropdownMenuItem
key="toggle-private"
className="space-x-2"
onClick={() => onSelectEditBucket()}
onClick={() => setModal(`edit`)}
>
<Edit2 size={14} />
<p>Edit bucket</p>
Expand All @@ -93,7 +91,7 @@ const BucketRow = ({
<DropdownMenuItem
key="empty-bucket"
className="space-x-2"
onClick={() => onSelectEmptyBucket()}
onClick={() => setModal(`empty`)}
>
<XCircle size={14} />
<p>Empty bucket</p>
Expand All @@ -103,7 +101,7 @@ const BucketRow = ({
<DropdownMenuItem
key="delete-bucket"
className="space-x-2"
onClick={() => onSelectDeleteBucket()}
onClick={() => setModal(`delete`)}
>
<Trash size={14} />
<p>Delete bucket</p>
Expand All @@ -113,6 +111,10 @@ const BucketRow = ({
) : (
<div className="w-7 mr-1" />
)}

<EditBucketModal visible={modal === `edit`} bucket={bucket} onClose={onClose} />
<EmptyBucketModal visible={modal === `empty`} bucket={bucket} onClose={onClose} />
<DeleteBucketModal visible={modal === `delete`} bucket={bucket} onClose={onClose} />
</div>
)
}
Expand Down
Loading
Loading