Page MenuHomePhorge

No OneTemporary

Size
31 KB
Referenced Files
None
Subscribers
None
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 1b133a089e..eb31f24185 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -1,467 +1,468 @@
/* global process */
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import vClickOutside from 'click-outside-vue3'
import VueVirtualScroller from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
import App from '../App.vue'
import routes from './routes'
import VBodyScrollLock from 'src/directives/body_scroll_lock'
import { windowWidth, windowHeight } from '../services/window_utils/window_utils'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import { applyConfig } from '../services/style_setter/style_setter.js'
import FaviconService from '../services/favicon_service/favicon_service.js'
import { initServiceWorker, updateFocus } from '../services/sw/sw.js'
import { useOAuthStore } from 'src/stores/oauth'
import { useI18nStore } from 'src/stores/i18n'
import { useInterfaceStore } from 'src/stores/interface'
import { useAnnouncementsStore } from 'src/stores/announcements'
+import { useAuthFlowStore } from 'src/stores/auth_flow'
let staticInitialResults = null
const parsedInitialResults = () => {
if (!document.getElementById('initial-results')) {
return null
}
if (!staticInitialResults) {
staticInitialResults = JSON.parse(document.getElementById('initial-results').textContent)
}
return staticInitialResults
}
const decodeUTF8Base64 = (data) => {
const rawData = atob(data)
const array = Uint8Array.from([...rawData].map((char) => char.charCodeAt(0)))
const text = new TextDecoder().decode(array)
return text
}
const preloadFetch = async (request) => {
const data = parsedInitialResults()
if (!data || !data[request]) {
return window.fetch(request)
}
const decoded = decodeUTF8Base64(data[request])
const requestData = JSON.parse(decoded)
return {
ok: true,
json: () => requestData,
text: () => requestData
}
}
const getInstanceConfig = async ({ store }) => {
try {
const res = await preloadFetch('/api/v1/instance')
if (res.ok) {
const data = await res.json()
const textlimit = data.max_toot_chars
const vapidPublicKey = data.pleroma.vapid_public_key
store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit })
store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required })
store.dispatch('setInstanceOption', { name: 'birthdayRequired', value: !!data.pleroma.metadata.birthday_required })
store.dispatch('setInstanceOption', { name: 'birthdayMinAge', value: data.pleroma.metadata.birthday_min_age || 0 })
if (vapidPublicKey) {
store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey })
}
} else {
throw (res)
}
} catch (error) {
console.error('Could not load instance config, potentially fatal')
console.error(error)
}
}
const getBackendProvidedConfig = async () => {
try {
const res = await window.fetch('/api/pleroma/frontend_configurations')
if (res.ok) {
const data = await res.json()
return data.pleroma_fe
} else {
throw (res)
}
} catch (error) {
console.error('Could not load backend-provided frontend config, potentially fatal')
console.error(error)
}
}
const getStaticConfig = async () => {
try {
const res = await window.fetch('/static/config.json')
if (res.ok) {
return res.json()
} else {
throw (res)
}
} catch (error) {
console.warn('Failed to load static/config.json, continuing without it.')
console.warn(error)
return {}
}
}
const setSettings = async ({ apiConfig, staticConfig, store }) => {
const overrides = window.___pleromafe_dev_overrides || {}
const env = window.___pleromafe_mode.NODE_ENV
// This takes static config and overrides properties that are present in apiConfig
let config = {}
if (overrides.staticConfigPreference && env === 'development') {
console.warn('OVERRIDING API CONFIG WITH STATIC CONFIG')
config = Object.assign({}, apiConfig, staticConfig)
} else {
config = Object.assign({}, staticConfig, apiConfig)
}
const copyInstanceOption = (name) => {
store.dispatch('setInstanceOption', { name, value: config[name] })
}
copyInstanceOption('theme')
copyInstanceOption('style')
copyInstanceOption('palette')
copyInstanceOption('embeddedToS')
copyInstanceOption('nsfwCensorImage')
copyInstanceOption('background')
copyInstanceOption('hidePostStats')
copyInstanceOption('hideBotIndication')
copyInstanceOption('hideUserStats')
copyInstanceOption('hideFilteredStatuses')
copyInstanceOption('logo')
store.dispatch('setInstanceOption', {
name: 'logoMask',
value: typeof config.logoMask === 'undefined'
? true
: config.logoMask
})
store.dispatch('setInstanceOption', {
name: 'logoMargin',
value: typeof config.logoMargin === 'undefined'
? 0
: config.logoMargin
})
copyInstanceOption('logoLeft')
- store.commit('authFlow/setInitialStrategy', config.loginMethod)
+ useAuthFlowStore().setInitialStrategy(config.loginMethod)
copyInstanceOption('redirectRootNoLogin')
copyInstanceOption('redirectRootLogin')
copyInstanceOption('showInstanceSpecificPanel')
copyInstanceOption('minimalScopesMode')
copyInstanceOption('hideMutedPosts')
copyInstanceOption('collapseMessageWithSubject')
copyInstanceOption('scopeCopy')
copyInstanceOption('subjectLineBehavior')
copyInstanceOption('postContentType')
copyInstanceOption('alwaysShowSubjectInput')
copyInstanceOption('showFeaturesPanel')
copyInstanceOption('hideSitename')
copyInstanceOption('sidebarRight')
}
const getTOS = async ({ store }) => {
try {
const res = await window.fetch('/static/terms-of-service.html')
if (res.ok) {
const html = await res.text()
store.dispatch('setInstanceOption', { name: 'tos', value: html })
} else {
throw (res)
}
} catch (e) {
console.warn("Can't load TOS\n", e)
}
}
const getInstancePanel = async ({ store }) => {
try {
const res = await preloadFetch('/instance/panel.html')
if (res.ok) {
const html = await res.text()
store.dispatch('setInstanceOption', { name: 'instanceSpecificPanelContent', value: html })
} else {
throw (res)
}
} catch (e) {
console.warn("Can't load instance panel\n", e)
}
}
const getStickers = async ({ store }) => {
try {
const res = await window.fetch('/static/stickers.json')
if (res.ok) {
const values = await res.json()
const stickers = (await Promise.all(
Object.entries(values).map(async ([name, path]) => {
const resPack = await window.fetch(path + 'pack.json')
let meta = {}
if (resPack.ok) {
meta = await resPack.json()
}
return {
pack: name,
path,
meta
}
})
)).sort((a, b) => {
return a.meta.title.localeCompare(b.meta.title)
})
store.dispatch('setInstanceOption', { name: 'stickers', value: stickers })
} else {
throw (res)
}
} catch (e) {
console.warn("Can't load stickers\n", e)
}
}
const getAppSecret = async ({ store }) => {
const oauth = useOAuthStore()
if (oauth.userToken) {
store.commit('setBackendInteractor', backendInteractorService(oauth.getToken))
}
}
const resolveStaffAccounts = ({ store, accounts }) => {
const nicknames = accounts.map(uri => uri.split('/').pop())
store.dispatch('setInstanceOption', { name: 'staffAccounts', value: nicknames })
}
const getNodeInfo = async ({ store }) => {
try {
const res = await preloadFetch('/nodeinfo/2.1.json')
if (res.ok) {
const data = await res.json()
const metadata = data.metadata
const features = metadata.features
store.dispatch('setInstanceOption', { name: 'name', value: metadata.nodeName })
store.dispatch('setInstanceOption', { name: 'registrationOpen', value: data.openRegistrations })
store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: features.includes('media_proxy') })
store.dispatch('setInstanceOption', { name: 'safeDM', value: features.includes('safe_dm_mentions') })
store.dispatch('setInstanceOption', { name: 'shoutAvailable', value: features.includes('chat') })
store.dispatch('setInstanceOption', { name: 'pleromaChatMessagesAvailable', value: features.includes('pleroma_chat_messages') })
store.dispatch('setInstanceOption', { name: 'pleromaCustomEmojiReactionsAvailable', value: features.includes('pleroma_custom_emoji_reactions') })
store.dispatch('setInstanceOption', { name: 'pleromaBookmarkFoldersAvailable', value: features.includes('pleroma:bookmark_folders') })
store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: features.includes('gopher') })
store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: features.includes('polls') })
store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') })
store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits })
store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled })
store.dispatch('setInstanceOption', { name: 'quotingAvailable', value: features.includes('quote_posting') })
store.dispatch('setInstanceOption', { name: 'groupActorAvailable', value: features.includes('pleroma:group_actors') })
const uploadLimits = metadata.uploadLimits
store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) })
store.dispatch('setInstanceOption', { name: 'avatarlimit', value: parseInt(uploadLimits.avatar) })
store.dispatch('setInstanceOption', { name: 'backgroundlimit', value: parseInt(uploadLimits.background) })
store.dispatch('setInstanceOption', { name: 'bannerlimit', value: parseInt(uploadLimits.banner) })
store.dispatch('setInstanceOption', { name: 'fieldsLimits', value: metadata.fieldsLimits })
store.dispatch('setInstanceOption', { name: 'restrictedNicknames', value: metadata.restrictedNicknames })
store.dispatch('setInstanceOption', { name: 'postFormats', value: metadata.postFormats })
const suggestions = metadata.suggestions
store.dispatch('setInstanceOption', { name: 'suggestionsEnabled', value: suggestions.enabled })
store.dispatch('setInstanceOption', { name: 'suggestionsWeb', value: suggestions.web })
const software = data.software
store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version })
store.dispatch('setInstanceOption', { name: 'backendRepository', value: software.repository })
store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: software.name === 'pleroma' })
const priv = metadata.private
store.dispatch('setInstanceOption', { name: 'private', value: priv })
const frontendVersion = window.___pleromafe_commit_hash
store.dispatch('setInstanceOption', { name: 'frontendVersion', value: frontendVersion })
const federation = metadata.federation
store.dispatch('setInstanceOption', {
name: 'tagPolicyAvailable',
value: typeof federation.mrf_policies === 'undefined'
? false
: metadata.federation.mrf_policies.includes('TagPolicy')
})
store.dispatch('setInstanceOption', { name: 'federationPolicy', value: federation })
store.dispatch('setInstanceOption', {
name: 'federating',
value: typeof federation.enabled === 'undefined'
? true
: federation.enabled
})
const accountActivationRequired = metadata.accountActivationRequired
store.dispatch('setInstanceOption', { name: 'accountActivationRequired', value: accountActivationRequired })
const accounts = metadata.staffAccounts
resolveStaffAccounts({ store, accounts })
} else {
throw (res)
}
} catch (e) {
console.warn('Could not load nodeinfo')
console.warn(e)
}
}
const setConfig = async ({ store }) => {
// apiConfig, staticConfig
const configInfos = await Promise.all([getBackendProvidedConfig({ store }), getStaticConfig()])
const apiConfig = configInfos[0]
const staticConfig = configInfos[1]
getAppSecret({ store })
await setSettings({ store, apiConfig, staticConfig })
}
const checkOAuthToken = async ({ store }) => {
const oauth = useOAuthStore()
if (oauth.getUserToken) {
return store.dispatch('loginUser', oauth.getUserToken)
}
return Promise.resolve()
}
const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
const app = createApp(App)
// Must have app use pinia before we do anything that touches the store
// https://pinia.vuejs.org/core-concepts/plugins.html#Introduction
// "Plugins are only applied to stores created after the plugins themselves, and after pinia is passed to the app, otherwise they won't be applied."
app.use(pinia)
const waitForAllStoresToLoad = async () => {
// the stores that do not persist technically do not need to be awaited here,
// but that involves either hard-coding the stores in some place (prone to errors)
// or writing another vite plugin to analyze which stores needs persisting (++load time)
const allStores = import.meta.glob('../stores/*.js', { eager: true })
if (process.env.NODE_ENV === 'development') {
// do some checks to avoid common errors
if (!Object.keys(allStores).length) {
throw new Error('No stores are available. Check the code in src/boot/after_store.js')
}
}
await Promise.all(
Object.entries(allStores)
.map(async ([name, mod]) => {
const isStoreName = name => name.startsWith('use')
if (process.env.NODE_ENV === 'development') {
if (Object.keys(mod).filter(isStoreName).length !== 1) {
throw new Error('Each store file must export exactly one store as a named export. Check your code in src/stores/')
}
}
const storeFuncName = Object.keys(mod).find(isStoreName)
if (storeFuncName && typeof mod[storeFuncName] === 'function') {
const p = mod[storeFuncName]().$persistLoaded
if (!(p instanceof Promise)) {
throw new Error(`${name} store's $persistLoaded is not a Promise. The persist plugin is not applied.`)
}
await p
} else {
throw new Error(`Store module ${name} does not export a 'use...' function`)
}
}))
}
try {
await waitForAllStoresToLoad()
} catch (e) {
console.error('Cannot load stores:', e)
storageError = e
}
if (storageError) {
useInterfaceStore().pushGlobalNotice({ messageKey: 'errors.storage_unavailable', level: 'error' })
}
useInterfaceStore().setLayoutWidth(windowWidth())
useInterfaceStore().setLayoutHeight(windowHeight())
FaviconService.initFaviconService()
initServiceWorker(store)
window.addEventListener('focus', () => updateFocus())
const overrides = window.___pleromafe_dev_overrides || {}
const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin
store.dispatch('setInstanceOption', { name: 'server', value: server })
await setConfig({ store })
try {
await useInterfaceStore().applyTheme().catch((e) => { console.error('Error setting theme', e) })
} catch (e) {
window.splashError(e)
return Promise.reject(e)
}
applyConfig(store.state.config, i18n.global)
// Now we can try getting the server settings and logging in
// Most of these are preloaded into the index.html so blocking is minimized
await Promise.all([
checkOAuthToken({ store }),
getInstancePanel({ store }),
getNodeInfo({ store }),
getInstanceConfig({ store })
]).catch(e => Promise.reject(e))
// Start fetching things that don't need to block the UI
store.dispatch('fetchMutes')
store.dispatch('loadDrafts')
useAnnouncementsStore().startFetchingAnnouncements()
getTOS({ store })
getStickers({ store })
const router = createRouter({
history: createWebHistory(),
routes: routes(store),
scrollBehavior: (to, _from, savedPosition) => {
if (to.matched.some(m => m.meta.dontScroll)) {
return false
}
return savedPosition || { left: 0, top: 0 }
}
})
useI18nStore().setI18n(i18n)
app.use(router)
app.use(store)
app.use(i18n)
// Little thing to get out of invalid theme state
window.resetThemes = () => {
useInterfaceStore().resetThemeV3()
useInterfaceStore().resetThemeV3Palette()
useInterfaceStore().resetThemeV2()
}
app.use(vClickOutside)
app.use(VBodyScrollLock)
app.use(VueVirtualScroller)
app.component('FAIcon', FontAwesomeIcon)
app.component('FALayers', FontAwesomeLayers)
// remove after vue 3.3
app.config.unwrapInjectedRef = true
app.mount('#app')
return app
}
export default afterStoreSetup
diff --git a/src/components/auth_form/auth_form.js b/src/components/auth_form/auth_form.js
index a86a3dca25..243cbf574c 100644
--- a/src/components/auth_form/auth_form.js
+++ b/src/components/auth_form/auth_form.js
@@ -1,27 +1,28 @@
import { h, resolveComponent } from 'vue'
import LoginForm from '../login_form/login_form.vue'
import MFARecoveryForm from '../mfa_form/recovery_form.vue'
import MFATOTPForm from '../mfa_form/totp_form.vue'
-import { mapGetters } from 'vuex'
+import { mapState } from 'pinia'
+import { useAuthFlowStore } from 'src/stores/auth_flow'
const AuthForm = {
name: 'AuthForm',
render () {
return h(resolveComponent(this.authForm))
},
computed: {
authForm () {
if (this.requiredTOTP) { return 'MFATOTPForm' }
if (this.requiredRecovery) { return 'MFARecoveryForm' }
return 'LoginForm'
},
- ...mapGetters('authFlow', ['requiredTOTP', 'requiredRecovery'])
+ ...mapState(useAuthFlowStore, ['requiredTOTP', 'requiredRecovery'])
},
components: {
MFARecoveryForm,
MFATOTPForm,
LoginForm
}
}
export default AuthForm
diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js
index ed3f5dfc68..9566aa9035 100644
--- a/src/components/login_form/login_form.js
+++ b/src/components/login_form/login_form.js
@@ -1,100 +1,98 @@
-import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
-import { mapStores } from 'pinia'
+import { mapState } from 'vuex'
+import { mapStores, mapActions, mapState as mapPiniaState } from 'pinia'
import oauthApi from '../../services/new_api/oauth.js'
import { useOAuthStore } from 'src/stores/oauth.js'
+import { useAuthFlowStore } from 'src/stores/auth_flow.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faTimes
} from '@fortawesome/free-solid-svg-icons'
library.add(
faTimes
)
const LoginForm = {
data: () => ({
user: {},
error: false
}),
computed: {
isPasswordAuth () { return this.requiredPassword },
isTokenAuth () { return this.requiredToken },
...mapStores(useOAuthStore),
...mapState({
registrationOpen: state => state.instance.registrationOpen,
instance: state => state.instance,
loggingIn: state => state.users.loggingIn,
}),
- ...mapGetters(
- 'authFlow', ['requiredPassword', 'requiredToken', 'requiredMFA']
- )
+ ...mapPiniaState(useAuthFlowStore, ['requiredPassword', 'requiredToken', 'requiredMFA'])
},
methods: {
- ...mapMutations('authFlow', ['requireMFA']),
- ...mapActions({ login: 'authFlow/login' }),
+ ...mapActions(useAuthFlowStore, ['requireMFA', 'login']),
submit () {
this.isTokenAuth ? this.submitToken() : this.submitPassword()
},
submitToken () {
const data = {
instance: this.instance.server,
commit: this.$store.commit
}
// NOTE: we do not really need the app token, but obtaining a token and
// calling verify_credentials is the only way to ensure the app still works.
this.oauthStore.ensureAppToken()
.then(() => {
const app = {
clientId: this.oauthStore.clientId,
clientSecret: this.oauthStore.clientSecret,
}
oauthApi.login({ ...app, ...data })
})
},
submitPassword () {
this.error = false
// NOTE: we do not really need the app token, but obtaining a token and
// calling verify_credentials is the only way to ensure the app still works.
this.oauthStore.ensureAppToken().then(() => {
const app = {
clientId: this.oauthStore.clientId,
clientSecret: this.oauthStore.clientSecret,
}
oauthApi.getTokenWithCredentials(
{
...app,
instance: this.instance.server,
username: this.user.username,
password: this.user.password
}
).then((result) => {
if (result.error) {
if (result.error === 'mfa_required') {
this.requireMFA({ settings: result })
} else if (result.identifier === 'password_reset_required') {
this.$router.push({ name: 'password-reset', params: { passwordResetRequested: true } })
} else {
this.error = result.error
this.focusOnPasswordInput()
}
return
}
this.login(result).then(() => {
this.$router.push({ name: 'friends' })
})
})
})
},
clearError () { this.error = false },
focusOnPasswordInput () {
const passwordInput = this.$refs.passwordInput
passwordInput.focus()
passwordInput.setSelectionRange(0, passwordInput.value.length)
}
}
}
export default LoginForm
diff --git a/src/components/mfa_form/recovery_form.js b/src/components/mfa_form/recovery_form.js
index 2d0f4fdff5..84479b1ec3 100644
--- a/src/components/mfa_form/recovery_form.js
+++ b/src/components/mfa_form/recovery_form.js
@@ -1,64 +1,64 @@
import mfaApi from '../../services/new_api/mfa.js'
-import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
-import { mapStores } from 'pinia'
+import { mapState } from 'vuex'
+import { mapStores, mapActions, mapState as mapPiniaState } from 'pinia'
import { useOAuthStore } from 'src/stores/oauth.js'
+import { useAuthFlowStore } from 'src/stores/auth_flow.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faTimes
} from '@fortawesome/free-solid-svg-icons'
library.add(
faTimes
)
export default {
data: () => ({
code: null,
error: false
}),
computed: {
- ...mapGetters({
- authSettings: 'authFlow/settings'
+ ...mapPiniaState(useAuthFlowStore, {
+ authSettings: store => store.settings
}),
...mapStores(useOAuthStore),
...mapState({
instance: 'instance',
})
},
methods: {
- ...mapMutations('authFlow', ['requireTOTP', 'abortMFA']),
- ...mapActions({ login: 'authFlow/login' }),
+ ...mapActions(useAuthFlowStore, ['requireTOTP', 'abortMFA', 'login']),
clearError () { this.error = false },
focusOnCodeInput () {
const codeInput = this.$refs.codeInput
codeInput.focus()
codeInput.setSelectionRange(0, codeInput.value.length)
},
submit () {
const { clientId, clientSecret } = this.oauthStore
const data = {
clientId,
clientSecret,
instance: this.instance.server,
mfaToken: this.authSettings.mfa_token,
code: this.code
}
mfaApi.verifyRecoveryCode(data).then((result) => {
if (result.error) {
this.error = result.error
this.code = null
this.focusOnCodeInput()
return
}
this.login(result).then(() => {
this.$router.push({ name: 'friends' })
})
})
}
}
}
diff --git a/src/components/mfa_form/totp_form.js b/src/components/mfa_form/totp_form.js
index 857d055ff1..e369d8a5d0 100644
--- a/src/components/mfa_form/totp_form.js
+++ b/src/components/mfa_form/totp_form.js
@@ -1,64 +1,64 @@
import mfaApi from '../../services/new_api/mfa.js'
-import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
-import { mapStores } from 'pinia'
+import { mapState } from 'vuex'
+import { mapStores, mapActions, mapState as mapPiniaState } from 'pinia'
import { useOAuthStore } from 'src/stores/oauth.js'
+import { useAuthFlowStore } from 'src/stores/auth_flow.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faTimes
} from '@fortawesome/free-solid-svg-icons'
library.add(
faTimes
)
export default {
data: () => ({
code: null,
error: false
}),
computed: {
- ...mapGetters({
- authSettings: 'authFlow/settings'
+ ...mapPiniaState(useAuthFlowStore, {
+ authSettings: store => store.settings
}),
...mapStores(useOAuthStore),
...mapState({
instance: 'instance',
})
},
methods: {
- ...mapMutations('authFlow', ['requireRecovery', 'abortMFA']),
- ...mapActions({ login: 'authFlow/login' }),
+ ...mapActions(useAuthFlowStore, ['requireRecovery', 'abortMFA', 'login']),
clearError () { this.error = false },
focusOnCodeInput () {
const codeInput = this.$refs.codeInput
codeInput.focus()
codeInput.setSelectionRange(0, codeInput.value.length)
},
submit () {
const { clientId, clientSecret } = this.oauthStore
const data = {
clientId,
clientSecret,
instance: this.instance.server,
mfaToken: this.authSettings.mfa_token,
code: this.code
}
mfaApi.verifyOTPCode(data).then((result) => {
if (result.error) {
this.error = result.error
this.code = null
this.focusOnCodeInput()
return
}
this.login(result).then(() => {
this.$router.push({ name: 'friends' })
})
})
}
}
}
diff --git a/src/modules/auth_flow.js b/src/modules/auth_flow.js
deleted file mode 100644
index dfa673db97..0000000000
--- a/src/modules/auth_flow.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import { useOAuthStore } from 'src/stores/oauth.js'
-
-const PASSWORD_STRATEGY = 'password'
-const TOKEN_STRATEGY = 'token'
-
-// MFA strategies
-const TOTP_STRATEGY = 'totp'
-const RECOVERY_STRATEGY = 'recovery'
-
-// initial state
-const state = {
- settings: {},
- strategy: PASSWORD_STRATEGY,
- initStrategy: PASSWORD_STRATEGY // default strategy from config
-}
-
-const resetState = (state) => {
- state.strategy = state.initStrategy
- state.settings = {}
-}
-
-// getters
-const getters = {
- settings: (state) => {
- return state.settings
- },
- requiredPassword: (state) => {
- return state.strategy === PASSWORD_STRATEGY
- },
- requiredToken: (state) => {
- return state.strategy === TOKEN_STRATEGY
- },
- requiredTOTP: (state) => {
- return state.strategy === TOTP_STRATEGY
- },
- requiredRecovery: (state) => {
- return state.strategy === RECOVERY_STRATEGY
- }
-}
-
-// mutations
-const mutations = {
- setInitialStrategy (state, strategy) {
- if (strategy) {
- state.initStrategy = strategy
- state.strategy = strategy
- }
- },
- requirePassword (state) {
- state.strategy = PASSWORD_STRATEGY
- },
- requireToken (state) {
- state.strategy = TOKEN_STRATEGY
- },
- requireMFA (state, { settings }) {
- state.settings = settings
- state.strategy = TOTP_STRATEGY // default strategy of MFA
- },
- requireRecovery (state) {
- state.strategy = RECOVERY_STRATEGY
- },
- requireTOTP (state) {
- state.strategy = TOTP_STRATEGY
- },
- abortMFA (state) {
- resetState(state)
- }
-}
-
-// actions
-const actions = {
-
- async login ({ state, dispatch }, { access_token: accessToken }) {
- useOAuthStore().setToken(accessToken)
- await dispatch('loginUser', accessToken, { root: true })
- resetState(state)
- }
-}
-
-export default {
- namespaced: true,
- state,
- getters,
- mutations,
- actions
-}
diff --git a/src/modules/index.js b/src/modules/index.js
index 7f0aa3706a..fd233585d6 100644
--- a/src/modules/index.js
+++ b/src/modules/index.js
@@ -1,25 +1,23 @@
import instance from './instance.js'
import statuses from './statuses.js'
import notifications from './notifications.js'
import users from './users.js'
import api from './api.js'
import config from './config.js'
import profileConfig from './profileConfig.js'
import adminSettings from './adminSettings.js'
-import authFlow from './auth_flow.js'
import drafts from './drafts.js'
import chats from './chats.js'
export default {
instance,
statuses,
notifications,
users,
api,
config,
profileConfig,
adminSettings,
- authFlow,
drafts,
chats
}
diff --git a/src/stores/auth_flow.js b/src/stores/auth_flow.js
new file mode 100644
index 0000000000..e41a9bc5e0
--- /dev/null
+++ b/src/stores/auth_flow.js
@@ -0,0 +1,69 @@
+import { useOAuthStore } from 'src/stores/oauth.js'
+import { defineStore } from 'pinia'
+
+const PASSWORD_STRATEGY = 'password'
+const TOKEN_STRATEGY = 'token'
+
+// MFA strategies
+const TOTP_STRATEGY = 'totp'
+const RECOVERY_STRATEGY = 'recovery'
+
+export const useAuthFlowStore = defineStore('authFlow', {
+ // initial state
+ state: () => ({
+ settings: {},
+ strategy: PASSWORD_STRATEGY,
+ initStrategy: PASSWORD_STRATEGY // default strategy from config
+ }),
+ // getters
+ getters: {
+ requiredPassword: (state) => {
+ return state.strategy === PASSWORD_STRATEGY
+ },
+ requiredToken: (state) => {
+ return state.strategy === TOKEN_STRATEGY
+ },
+ requiredTOTP: (state) => {
+ return state.strategy === TOTP_STRATEGY
+ },
+ requiredRecovery: (state) => {
+ return state.strategy === RECOVERY_STRATEGY
+ },
+ },
+ actions: {
+ setInitialStrategy (strategy) {
+ if (strategy) {
+ this.initStrategy = strategy
+ this.strategy = strategy
+ }
+ },
+ requirePassword () {
+ this.strategy = PASSWORD_STRATEGY
+ },
+ requireToken () {
+ this.strategy = TOKEN_STRATEGY
+ },
+ requireMFA ({ settings }) {
+ this.settings = settings
+ this.strategy = TOTP_STRATEGY // default strategy of MFA
+ },
+ requireRecovery () {
+ this.strategy = RECOVERY_STRATEGY
+ },
+ requireTOTP () {
+ this.strategy = TOTP_STRATEGY
+ },
+ abortMFA () {
+ this.resetState()
+ },
+ resetState () {
+ this.strategy = this.initStrategy
+ this.settings = {}
+ },
+ async login ({ access_token: accessToken }) {
+ useOAuthStore().setToken(accessToken)
+ await window.vuex.dispatch('loginUser', accessToken, { root: true })
+ this.resetState()
+ }
+ }
+})
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Fri, Oct 9, 8:43 AM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1784587
Default Alt Text
(31 KB)

Event Timeline