Implement cli and web token revoking
This commit is contained in:
@@ -51,6 +51,20 @@
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<h2>{{ $t('profile.appPasswords.title') }}</h2>
|
||||
<Card>
|
||||
</Card>
|
||||
|
||||
<h2 v-show="user.isAtLeastAdmin">{{ $t('profile.apiTokens.title') }}</h2>
|
||||
<Card v-show="user.isAtLeastAdmin">
|
||||
</Card>
|
||||
|
||||
<h2>{{ $t('profile.loginTokens.title') }}</h2>
|
||||
<Card>
|
||||
<p>{{ $t('profile.loginTokens.description', { webadminTokenCount: webadminTokens.length, cliTokenCount: cliTokens.length }) }}</p>
|
||||
<Button danger :loading="revokeTokensBusy" :disabled="revokeTokensBusy" @click="onRevokeAllWebAndCliTokens()">{{ $t('profile.loginTokens.logoutAll') }}</Button>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -59,9 +73,11 @@
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { ref, onMounted, useTemplateRef } from 'vue';
|
||||
import { Button, Dropdown, InputDialog } from 'pankow';
|
||||
import { TOKEN_TYPES } from '../constants.js';
|
||||
import Card from './Card.vue';
|
||||
import ProfileModel from '../models/ProfileModel.js';
|
||||
import CloudronModel from '../models/CloudronModel.js';
|
||||
import TokensModel from '../models/TokensModel.js';
|
||||
|
||||
const i18n = useI18n();
|
||||
const t = i18n.t;
|
||||
@@ -70,33 +86,15 @@ const API_ORIGIN = import.meta.env.VITE_API_ORIGIN ? import.meta.env.VITE_API_OR
|
||||
|
||||
const profileModel = ProfileModel.create(API_ORIGIN, localStorage.token);
|
||||
const cloudronModel = CloudronModel.create(API_ORIGIN, localStorage.token);
|
||||
const tokensModel = TokensModel.create(API_ORIGIN, localStorage.token);
|
||||
|
||||
// TODO what is this?
|
||||
const config = ref({});
|
||||
|
||||
const config = ref({}); // TODO what is this?
|
||||
const user = ref({});
|
||||
|
||||
const inputDialog = useTemplateRef('inputDialog');
|
||||
|
||||
const languages = ref([]);
|
||||
const language = ref('');
|
||||
const inputDialog = useTemplateRef('inputDialog');
|
||||
const avatarFileInput = useTemplateRef('avatarFileInput');
|
||||
|
||||
onMounted(async () => {
|
||||
user.value = await profileModel.get();
|
||||
|
||||
const langs = await cloudronModel.languages();
|
||||
languages.value = langs.map(l => {
|
||||
return {
|
||||
id: l,
|
||||
display: t(`lang.${l}`)
|
||||
};
|
||||
}).sort((a, b) => {
|
||||
return a.display.localeCompare(b.display);
|
||||
});
|
||||
|
||||
const usedLang = window.localStorage.NG_TRANSLATE_LANG_KEY || 'en';
|
||||
language.value = languages.value.find(l => l.id === usedLang).id;
|
||||
});
|
||||
|
||||
async function onSelectLanguage(lang) {
|
||||
window.localStorage.NG_TRANSLATE_LANG_KEY = lang.id;
|
||||
|
||||
@@ -190,6 +188,7 @@ async function onLogout() {
|
||||
await profileModel.logout();
|
||||
}
|
||||
|
||||
const avatarFileInput = useTemplateRef('avatarFileInput');
|
||||
async function onAvatarChanged() {
|
||||
if (!avatarFileInput.value.files[0]) return;
|
||||
await profileModel.setAvatar(avatarFileInput.value.files[0]);
|
||||
@@ -200,6 +199,47 @@ async function onAvatarChanged() {
|
||||
user.value.avatarUrl = u.toString();
|
||||
}
|
||||
|
||||
// Tokens
|
||||
const webadminTokens = ref([]);
|
||||
const cliTokens = ref([]);
|
||||
const apiTokens = ref([]);
|
||||
const revokeTokensBusy = ref(false);
|
||||
async function onRevokeAllWebAndCliTokens() {
|
||||
revokeTokensBusy.value = true;
|
||||
|
||||
// filter current access token to be able to logout still
|
||||
const tokens = webadminTokens.value.concat(cliTokens.value).filter(t => t.accessToken !== localStorage.token);
|
||||
for (const token of tokens) {
|
||||
await tokensModel.remove(token.id);
|
||||
}
|
||||
|
||||
await profileModel.logout();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
user.value = await profileModel.get();
|
||||
|
||||
const langs = await cloudronModel.languages();
|
||||
languages.value = langs.map(l => {
|
||||
return {
|
||||
id: l,
|
||||
display: t(`lang.${l}`)
|
||||
};
|
||||
}).sort((a, b) => {
|
||||
return a.display.localeCompare(b.display);
|
||||
});
|
||||
|
||||
const usedLang = window.localStorage.NG_TRANSLATE_LANG_KEY || 'en';
|
||||
language.value = languages.value.find(l => l.id === usedLang).id;
|
||||
|
||||
const tokens = await tokensModel.list();
|
||||
|
||||
// dashboard and development clientIds were issued with 7.5.0
|
||||
webadminTokens.value = tokens.filter(function (c) { return c.clientId === TOKEN_TYPES.ID_WEBADMIN || c.clientId === TOKEN_TYPES.ID_DEVELOPMENT || c.clientId === 'dashboard' || c.clientId === 'development'; });
|
||||
cliTokens.value = tokens.filter(function (c) { return c.clientId === TOKEN_TYPES.ID_CLI; });
|
||||
apiTokens.value = tokens.filter(function (c) { return c.clientId === TOKEN_TYPES.ID_SDK; });
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user