Skip to content

Commit

Permalink
feat: renterd key management
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfreska committed Jan 17, 2024
1 parent 0aaec35 commit 891abb0
Show file tree
Hide file tree
Showing 22 changed files with 929 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/fair-steaks-film.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'renterd': minor
---

S3 authentication keypairs can now be created and managed directly from the UI. Closes https://github.com/SiaFoundation/web/issues/430
14 changes: 14 additions & 0 deletions apps/renterd/components/CmdRoot/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { FilesCmd } from '../Files/FilesCmd'
import { useHosts } from '../../contexts/hosts'
import { useDebounce } from 'use-debounce'
import { CmdEmptyDefault } from './CmdEmpty'
import { KeysCmd } from '../Keys/KeysCmd'

type Props = {
panel?: boolean
Expand Down Expand Up @@ -131,6 +132,19 @@ export function CmdRoot({ panel }: Props) {
afterSelect()
}}
/>
<KeysCmd
currentPage={page}
pushPage={pushPage}
beforeSelect={() => {
beforeSelect()
}}
afterSelect={() => {
if (!router.pathname.startsWith(routes.keys.index)) {
router.push(routes.keys.index)
}
afterSelect()
}}
/>
<ConfigCmdGroup currentPage={page} pushPage={pushPage} />
<NodeCmdGroup currentPage={page} pushPage={pushPage} />
</Command.List>
Expand Down
97 changes: 97 additions & 0 deletions apps/renterd/components/Keys/KeyContextMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {
DropdownMenu,
DropdownMenuItem,
Button,
DropdownMenuLeftSlot,
DropdownMenuLabel,
Text,
Paragraph,
triggerSuccessToast,
triggerErrorToast,
truncate,
} from '@siafoundation/design-system'
import { Draggable16, Delete16 } from '@siafoundation/react-icons'
import { useSettingUpdate } from '@siafoundation/react-renterd'
import { useS3AuthenticationSettings } from '../../hooks/useS3AuthenticationSettings'
import { useCallback } from 'react'
import { omit } from '@technically/lodash'
import { useDialog } from '../../contexts/dialog'

type Props = {
s3Key: string
contentProps?: React.ComponentProps<typeof DropdownMenu>['contentProps']
buttonProps?: React.ComponentProps<typeof Button>
}

export function KeyContextMenu({ s3Key, contentProps, buttonProps }: Props) {
const { openConfirmDialog } = useDialog()
const s3AuthenticationSettings = useS3AuthenticationSettings()
const update = useSettingUpdate()
const deleteKey = useCallback(async () => {
const newKeys = omit(s3AuthenticationSettings.data?.v4Keypairs, s3Key)
const response = await update.put({
params: {
key: 's3authentication',
},
payload: {
v4Keypairs: newKeys,
},
})
if (response.error) {
triggerErrorToast(`Failed to delete key: ${response.error}`)
} else {
triggerSuccessToast(`Key ${s3Key} removed.`)
}
}, [s3AuthenticationSettings.data, s3Key, update])

return (
<DropdownMenu
trigger={
<Button variant="ghost" icon="hover" {...buttonProps}>
<Draggable16 />
</Button>
}
contentProps={{
align: 'start',
...contentProps,
onClick: (e) => {
e.stopPropagation()
},
}}
>
<div className="px-1.5 py-1">
<Text size="14" weight="medium" color="subtle">
Key {s3Key.slice(0, 24)}...
</Text>
</div>
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem
onSelect={() => {
openConfirmDialog({
title: `Delete key ${truncate(s3Key, 15)}`,
action: 'Remove',
variant: 'red',
body: (
<div className="flex flex-col gap-1">
<Paragraph size="14">
Are you sure you would like to remove the following key?
</Paragraph>
<Paragraph size="14" font="mono">
{truncate(s3Key, 80)}
</Paragraph>
</div>
),
onConfirm: async () => {
deleteKey()
},
})
}}
>
<DropdownMenuLeftSlot>
<Delete16 />
</DropdownMenuLeftSlot>
Delete key
</DropdownMenuItem>
</DropdownMenu>
)
}
17 changes: 17 additions & 0 deletions apps/renterd/components/Keys/KeysActionsMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Button } from '@siafoundation/design-system'
import { KeysViewDropdownMenu } from './KeysViewDropdownMenu'
import { Add16 } from '@siafoundation/react-icons'
import { useDialog } from '../../contexts/dialog'

export function KeysActionsMenu() {
const { openDialog } = useDialog()
return (
<div className="flex gap-2">
<Button onClick={() => openDialog('keysCreate')}>
<Add16 />
Create keypair
</Button>
<KeysViewDropdownMenu />
</div>
)
}
65 changes: 65 additions & 0 deletions apps/renterd/components/Keys/KeysCmd/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {
CommandGroup,
CommandItemNav,
CommandItemSearch,
} from '../../CmdRoot/Item'
import { Page } from '../../CmdRoot/types'
import { useRouter } from 'next/router'
import { useDialog } from '../../../contexts/dialog'
import { routes } from '../../../config/routes'

export const commandPage = {
namespace: 'keys',
label: 'S3 authentication keys',
}

export function KeysCmd({
currentPage,
parentPage,
pushPage,
}: {
currentPage: Page
parentPage?: Page
beforeSelect?: () => void
afterSelect?: () => void
pushPage: (page: Page) => void
}) {
const router = useRouter()
const { closeDialog, openDialog } = useDialog()
return (
<>
<CommandItemNav
currentPage={currentPage}
parentPage={parentPage}
commandPage={parentPage}
onSelect={() => {
pushPage(commandPage)
}}
>
{commandPage.label}
</CommandItemNav>
<CommandGroup currentPage={currentPage} commandPage={commandPage}>
<CommandItemSearch
currentPage={currentPage}
commandPage={commandPage}
onSelect={() => {
router.push(routes.keys.index)
closeDialog()
}}
>
View keys
</CommandItemSearch>
<CommandItemSearch
currentPage={currentPage}
commandPage={commandPage}
onSelect={() => {
router.push(routes.keys.index)
openDialog('keysCreate')
}}
>
Create new S3 authentication keypair
</CommandItemSearch>
</CommandGroup>
</>
)
}
Loading

0 comments on commit 891abb0

Please sign in to comment.