Skip to content
Closed
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
6 changes: 5 additions & 1 deletion appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
declare(strict_types=1);
return [
'resources' => [
'AuthSettings' => ['url' => '/authtokens' , 'root' => ''],
// Apparently has the convention calling AuthSettingsController.destroy() on DELETE
'AuthSettings' => ['url' => '/authtokens' , 'root' => ''],
],
'routes' => [
['name' => 'AuthSettings#wipe', 'url' => '/authtokens/wipe/{id}', 'verb' => 'POST' , 'root' => ''],
]
];
2 changes: 1 addition & 1 deletion src/components/security/AuthToken.vue
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ export default defineComponent({
},
wipe() {
this.actionOpen = false
this.authTokenStore.wipeToken(this.token)
this.$emit('wipe', this.token)
},
},
})
Expand Down
1 change: 1 addition & 0 deletions src/components/security/AuthTokenList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<tbody class="token-list__body">
<AuthToken v-for="token in sortedTokens"
:key="token.id"
@wipe="$emit('wipe', ...arguments)"
:token="token" />
</tbody>
</table>
Expand Down
61 changes: 60 additions & 1 deletion src/components/security/AuthTokenSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,38 @@
<p class="settings-hint hidden-when-empty">
{{ t('simplesettings', 'Web, desktop and mobile clients currently logged in to your account.') }}
</p>
<AuthTokenList />
<AuthTokenList @wipe="doWipe" />
<AuthTokenSetup v-if="canCreateToken" />
<NcDialog
:open.sync="confirmingWipe"
:name="t('simplesettings', 'Confirm wipe')"
content-classes="wipe-dialog">
{{ t('simplesettings', 'Do you really want to wipe your data from this device?') }}
<div class="button-row">
<NcButton
@click="cancelWipe">
{{ t('simplesettings', 'Cancel') }}
</NcButton>

<NcButton icon="icon-delete"
@click="confirmedWipe">
{{ t('simplesettings', 'Confirm wipe') }}
</NcButton>
</div>
</NcDialog>
</div>
</template>

<script lang="ts">
// @ts-expect-error: Cannot find module or its corresponding type declarations.
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
// @ts-expect-error: Cannot find module or its corresponding type declarations.
import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js'

import { confirmPassword } from '@nextcloud/password-confirmation'
import { loadState } from '@nextcloud/initial-state'
import { translate as t } from '@nextcloud/l10n'
import { useAuthTokenStore, type IToken } from '../../store/authtoken'
import { defineComponent } from 'vue'

import AuthTokenList from './AuthTokenList.vue'
Expand All @@ -42,16 +66,51 @@ import AuthTokenSetup from './AuthTokenSetup.vue'
export default defineComponent({
name: 'AuthTokenSection',
components: {
NcButton,
NcDialog,
AuthTokenList,
AuthTokenSetup,
},
setup() {
const authTokenStore = useAuthTokenStore()
return { authTokenStore }
},
data() {
return {
canCreateToken: loadState('simplesettings', 'can_create_app_token'),
tokenToBeWiped: null as IToken | null,
confirmingWipe: false,
}
},
methods: {
t,
async doWipe(token: IToken) {
this.tokenToBeWiped = token
this.confirmingWipe = true

await confirmPassword()
},
async cancelWipe() {
this.tokenToBeWiped = null
this.confirmingWipe = false
},
async confirmedWipe() {
if (this.tokenToBeWiped === null) {
return
}
await this.authTokenStore.wipeToken(this.tokenToBeWiped as IToken)
this.tokenToBeWiped = null
this.confirmingWipe = false
},
},
})
</script>

<style scoped>
.button-row {
display: flex;
flex-direction: row;
margin: 10px 0;
gap: 4px;
}
</style>
2 changes: 2 additions & 0 deletions src/components/security/AuthTokenSetup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

<script lang="ts">
import { showError } from '@nextcloud/dialogs'
import { confirmPassword } from '@nextcloud/password-confirmation'
import { translate as t } from '@nextcloud/l10n'
import { defineComponent } from 'vue'
import { useAuthTokenStore, type ITokenResponse } from '../../store/authtoken'
Expand Down Expand Up @@ -77,6 +78,7 @@ export default defineComponent({
async submit() {
try {
this.loading = true
await confirmPassword()
this.newToken = await this.authTokenStore.addToken(this.deviceName)
} catch (error) {
logger.error(error as Error)
Expand Down
17 changes: 0 additions & 17 deletions src/oc.d.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1 @@
/// <reference types="@nextcloud/typings" />

declare namespace Nextcloud29WithPolyfills {
interface DialogsPolyfill {
confirm(
title: string,
message: string,
callback: () => void,
modal: boolean): void;
}

interface OC extends Nextcloud.v29.OC {
dialogs: Nextcloud.Common.Dialogs & DialogsPolyfill;
}
}

// eslint-disable-next-line no-var
declare var OC: Nextcloud29WithPolyfills
21 changes: 0 additions & 21 deletions src/store/authtoken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import { showError } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state'
import { translate as t } from '@nextcloud/l10n'
import { confirmPassword } from '@nextcloud/password-confirmation'
import { generateUrl } from '@nextcloud/router'
import { defineStore } from 'pinia'

Expand All @@ -31,17 +30,6 @@ import logger from '../logger'

const BASE_URL = generateUrl('/apps/simplesettings/authtokens')

const confirm = () => {
return new Promise(resolve => {
window.OC.dialogs.confirm(
t('simplesettings', 'Do you really want to wipe your data from this device?'),
t('simplesettings', 'Confirm wipe'),
resolve,
true,
)
})
}

export enum TokenType {
TEMPORARY_TOKEN = 0,
PERMANENT_TOKEN = 1,
Expand Down Expand Up @@ -101,8 +89,6 @@ export const useAuthTokenStore = defineStore('auth-token', {
logger.debug('Creating a new app token')

try {
await confirmPassword()

const { data } = await axios.post<ITokenResponse>(BASE_URL, { name })
this.tokens.push(data.deviceToken)
logger.debug('App token created')
Expand Down Expand Up @@ -142,13 +128,6 @@ export const useAuthTokenStore = defineStore('auth-token', {
logger.debug('Wiping app token', { token })

try {
await confirmPassword()

if (!(await confirm())) {
logger.debug('Wipe aborted by user')
return
}

await axios.post(`${BASE_URL}/wipe/${token.id}`)
logger.debug('App token marked for wipe', { token })

Expand Down