[refactor] Remove authorize store
This commit is contained in:
parent
b46c9c2e91
commit
df5ecdf9fd
|
@ -11,7 +11,7 @@ export const insertAccount = (
|
||||||
clientSecret: string,
|
clientSecret: string,
|
||||||
accessToken: string,
|
accessToken: string,
|
||||||
refreshToken: string | null,
|
refreshToken: string | null,
|
||||||
server: LocalServer
|
serverId: number
|
||||||
): Promise<LocalAccount> => {
|
): Promise<LocalAccount> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
db.serialize(() => {
|
db.serialize(() => {
|
||||||
|
@ -34,13 +34,12 @@ export const insertAccount = (
|
||||||
}
|
}
|
||||||
const id = this.lastID
|
const id = this.lastID
|
||||||
|
|
||||||
db.run('UPDATE servers SET account_id = ? WHERE id = ?', [id, server.id], err => {
|
db.run('UPDATE servers SET account_id = ? WHERE id = ?', [id, serverId], err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err)
|
reject(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
db.run('COMMIT')
|
db.run('COMMIT')
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
id,
|
id,
|
||||||
username,
|
username,
|
||||||
|
@ -164,6 +163,9 @@ FROM accounts INNER JOIN servers ON servers.account_id = accounts.id WHERE accou
|
||||||
|
|
||||||
export const removeAccount = (db: sqlite3.Database, id: number): Promise<null> => {
|
export const removeAccount = (db: sqlite3.Database, id: number): Promise<null> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
db.serialize(() => {
|
||||||
|
db.run('PRAGMA foreign_keys = ON')
|
||||||
|
|
||||||
db.run('DELETE FROM accounts WHERE id = ?', id, err => {
|
db.run('DELETE FROM accounts WHERE id = ?', id, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err)
|
reject(err)
|
||||||
|
@ -171,10 +173,14 @@ export const removeAccount = (db: sqlite3.Database, id: number): Promise<null> =
|
||||||
resolve(null)
|
resolve(null)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const removeAllAccounts = (db: sqlite3.Database): Promise<null> => {
|
export const removeAllAccounts = (db: sqlite3.Database): Promise<null> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
db.serialize(() => {
|
||||||
|
db.run('PRAGMA foreign_keys = ON')
|
||||||
|
|
||||||
db.run('DELETE FROM accounts', err => {
|
db.run('DELETE FROM accounts', err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err)
|
reject(err)
|
||||||
|
@ -182,6 +188,7 @@ export const removeAllAccounts = (db: sqlite3.Database): Promise<null> => {
|
||||||
resolve(null)
|
resolve(null)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const forwardAccount = (db: sqlite3.Database, id: number): Promise<null> => {
|
export const forwardAccount = (db: sqlite3.Database, id: number): Promise<null> => {
|
||||||
|
|
|
@ -53,6 +53,9 @@ export const insertTag = (db: sqlite3.Database, accountId: number, tag: string):
|
||||||
|
|
||||||
export const removeTag = (db: sqlite3.Database, tag: LocalTag): Promise<null> => {
|
export const removeTag = (db: sqlite3.Database, tag: LocalTag): Promise<null> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
db.serialize(() => {
|
||||||
|
db.run('PRAGMA foreign_keys = ON')
|
||||||
|
|
||||||
db.run('DELETE FROM hashtags WHERE id = ?', tag.id, err => {
|
db.run('DELETE FROM hashtags WHERE id = ?', tag.id, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err)
|
reject(err)
|
||||||
|
@ -60,4 +63,5 @@ export const removeTag = (db: sqlite3.Database, tag: LocalTag): Promise<null> =>
|
||||||
resolve(null)
|
resolve(null)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -463,26 +463,28 @@ ipcMain.handle('add-app', async (_: IpcMainInvokeEvent, url: string) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
type AuthorizeRequest = {
|
type AuthorizeRequest = {
|
||||||
server: LocalServer
|
serverID: number
|
||||||
appData: OAuth.AppData
|
baseURL: string
|
||||||
|
clientID: string
|
||||||
|
clientSecret: string
|
||||||
code: string
|
code: string
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle('authorize', async (_: IpcMainInvokeEvent, req: AuthorizeRequest) => {
|
ipcMain.handle('authorize', async (_: IpcMainInvokeEvent, req: AuthorizeRequest) => {
|
||||||
const proxy = await proxyConfiguration.forMastodon()
|
const proxy = await proxyConfiguration.forMastodon()
|
||||||
const sns = await detector(req.server.baseURL, proxy)
|
const sns = await detector(req.baseURL, proxy)
|
||||||
const client = generator(sns, req.server.baseURL, null, 'Whalebird', proxy)
|
const client = generator(sns, req.baseURL, null, 'Whalebird', proxy)
|
||||||
const tokenData = await client.fetchAccessToken(req.appData.client_id, req.appData.client_secret, req.code, 'urn:ietf:wg:oauth:2.0:oob')
|
const tokenData = await client.fetchAccessToken(req.clientID, req.clientSecret, req.code, 'urn:ietf:wg:oauth:2.0:oob')
|
||||||
let accessToken = tokenData.access_token
|
let accessToken = tokenData.access_token
|
||||||
if (sns === 'misskey') {
|
if (sns === 'misskey') {
|
||||||
// In misskey, access token is sha256(userToken + clientSecret)
|
// In misskey, access token is sha256(userToken + clientSecret)
|
||||||
accessToken = crypto
|
accessToken = crypto
|
||||||
.createHash('sha256')
|
.createHash('sha256')
|
||||||
.update(tokenData.access_token + req.appData.client_secret, 'utf8')
|
.update(tokenData.access_token + req.clientSecret, 'utf8')
|
||||||
.digest('hex')
|
.digest('hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
const authorizedClient = generator(sns, req.server.baseURL, accessToken, 'Whalebird', proxy)
|
const authorizedClient = generator(sns, req.baseURL, accessToken, 'Whalebird', proxy)
|
||||||
const credentials = await authorizedClient.verifyAccountCredentials()
|
const credentials = await authorizedClient.verifyAccountCredentials()
|
||||||
|
|
||||||
const account = await insertAccount(
|
const account = await insertAccount(
|
||||||
|
@ -490,11 +492,11 @@ ipcMain.handle('authorize', async (_: IpcMainInvokeEvent, req: AuthorizeRequest)
|
||||||
credentials.data.username,
|
credentials.data.username,
|
||||||
credentials.data.id,
|
credentials.data.id,
|
||||||
credentials.data.avatar,
|
credentials.data.avatar,
|
||||||
req.appData.client_id,
|
req.clientID,
|
||||||
req.appData.client_secret,
|
req.clientSecret,
|
||||||
accessToken,
|
accessToken,
|
||||||
tokenData.refresh_token,
|
tokenData.refresh_token,
|
||||||
req.server
|
req.serverID
|
||||||
)
|
)
|
||||||
return account
|
return account
|
||||||
})
|
})
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<FailoverImg :src="`${server.baseURL}/favicon.ico`" :failoverSrc="`${server.baseURL}/favicon.png`" class="instance-icon" />
|
<FailoverImg :src="`${server.baseURL}/favicon.ico`" :failoverSrc="`${server.baseURL}/favicon.png`" class="instance-icon" />
|
||||||
<span>{{ server.domain }}</span>
|
<span>{{ server.domain }}</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/login" :title="$t('global_header.add_new_account')" role="menuitem" class="add-new-account">
|
<el-menu-item index="/login/form" :title="$t('global_header.add_new_account')" role="menuitem" class="add-new-account">
|
||||||
<font-awesome-icon icon="plus" />
|
<font-awesome-icon icon="plus" />
|
||||||
<span>New</span>
|
<span>New</span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
@ -71,7 +71,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(_ => {
|
.catch(_ => {
|
||||||
return router.push({ path: '/login' })
|
return router.push({ path: '/login/form' })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,38 +10,27 @@
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-container>
|
<el-container>
|
||||||
<login-form v-if="appData === null" />
|
<router-view />
|
||||||
<authorize v-else />
|
|
||||||
</el-container>
|
</el-container>
|
||||||
</el-container>
|
</el-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, computed } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useStore } from '@/store'
|
|
||||||
import { useMagicKeys, whenever } from '@vueuse/core'
|
import { useMagicKeys, whenever } from '@vueuse/core'
|
||||||
import LoginForm from './Login/LoginForm.vue'
|
|
||||||
import Authorize from './Login/Authorize.vue'
|
|
||||||
import { ACTION_TYPES } from '@/store/Login'
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'login',
|
name: 'login',
|
||||||
components: { LoginForm, Authorize },
|
|
||||||
setup() {
|
setup() {
|
||||||
const space = 'Login'
|
|
||||||
const store = useStore()
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { escape } = useMagicKeys()
|
const { escape } = useMagicKeys()
|
||||||
|
|
||||||
const appData = computed(() => store.state.Login.appData)
|
|
||||||
|
|
||||||
whenever(escape, () => {
|
whenever(escape, () => {
|
||||||
close()
|
close()
|
||||||
})
|
})
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
store.dispatch(`${space}/${ACTION_TYPES.PAGE_BACK}`)
|
|
||||||
return router.push({
|
return router.push({
|
||||||
path: '/',
|
path: '/',
|
||||||
query: { redirect: 'home' }
|
query: { redirect: 'home' }
|
||||||
|
@ -49,8 +38,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
close,
|
close
|
||||||
appData
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
class="authorize-form"
|
class="authorize-form"
|
||||||
@submit.prevent="authorizeSubmit"
|
@submit.prevent="authorizeSubmit"
|
||||||
>
|
>
|
||||||
<p v-if="sns === 'misskey'">{{ $t('authorize.misskey_label') }}</p>
|
<p v-if="$route.query.sns === 'misskey'">{{ $t('authorize.misskey_label') }}</p>
|
||||||
<el-form-item :label="$t('authorize.code_label')" v-else>
|
<el-form-item :label="$t('authorize.code_label')" v-else>
|
||||||
<el-input v-model="authorizeForm.code"></el-input>
|
<el-input v-model="authorizeForm.code"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -37,27 +37,25 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref, reactive, computed } from 'vue'
|
import { defineComponent, ref, reactive } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useI18next } from 'vue3-i18next'
|
import { useI18next } from 'vue3-i18next'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { useMagicKeys, whenever } from '@vueuse/core'
|
import { useMagicKeys, whenever } from '@vueuse/core'
|
||||||
import { useStore } from '@/store'
|
import { MyWindow } from '~/src/types/global'
|
||||||
import { ACTION_TYPES } from '@/store/Login'
|
import { LocalAccount } from '~/src/types/localAccount'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Authorize',
|
name: 'Authorize',
|
||||||
setup() {
|
setup() {
|
||||||
const space = 'Login'
|
const win = (window as any) as MyWindow
|
||||||
const store = useStore()
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
const i18n = useI18next()
|
const i18n = useI18next()
|
||||||
const { escape } = useMagicKeys()
|
const { escape } = useMagicKeys()
|
||||||
|
|
||||||
const sns = computed(() => store.state.Login.sns)
|
|
||||||
|
|
||||||
const authorizeForm = reactive({
|
const authorizeForm = reactive({
|
||||||
code: null
|
code: ''
|
||||||
})
|
})
|
||||||
const submitting = ref<boolean>(false)
|
const submitting = ref<boolean>(false)
|
||||||
|
|
||||||
|
@ -65,23 +63,30 @@ export default defineComponent({
|
||||||
close()
|
close()
|
||||||
})
|
})
|
||||||
|
|
||||||
const authorizeSubmit = () => {
|
const authorizeSubmit = async () => {
|
||||||
submitting.value = true
|
submitting.value = true
|
||||||
store
|
let code = authorizeForm.code
|
||||||
.dispatch(`${space}/${ACTION_TYPES.AUTHORIZE}`, authorizeForm.code)
|
if (route.query.sns === 'misskey' && route.query.session_token) {
|
||||||
.finally(() => {
|
code = route.query.session_token.toString()
|
||||||
submitting.value = false
|
}
|
||||||
|
try {
|
||||||
|
const localAccount: LocalAccount = await win.ipcRenderer.invoke('authorize', {
|
||||||
|
serverID: route.query.server_id,
|
||||||
|
baseURL: route.query.base_url,
|
||||||
|
clientID: route.query.client_id,
|
||||||
|
clientSecret: route.query.client_secret,
|
||||||
|
code: code
|
||||||
})
|
})
|
||||||
.then(id => {
|
router.push({ path: `/${localAccount.id}/home` })
|
||||||
router.push({ path: `/${id}/home` })
|
} catch (err) {
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err)
|
console.error(err)
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: i18n.t('message.authorize_error'),
|
message: i18n.t('message.authorize_error'),
|
||||||
type: 'error'
|
type: 'error'
|
||||||
})
|
})
|
||||||
})
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
|
@ -92,8 +97,7 @@ export default defineComponent({
|
||||||
authorizeForm,
|
authorizeForm,
|
||||||
submitting,
|
submitting,
|
||||||
authorizeSubmit,
|
authorizeSubmit,
|
||||||
close,
|
close
|
||||||
sns
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -40,25 +40,28 @@
|
||||||
import { defineComponent, computed, reactive, ref } from 'vue'
|
import { defineComponent, computed, reactive, ref } from 'vue'
|
||||||
import { useI18next } from 'vue3-i18next'
|
import { useI18next } from 'vue3-i18next'
|
||||||
import { ElLoading, ElMessage, FormInstance, FormRules } from 'element-plus'
|
import { ElLoading, ElMessage, FormInstance, FormRules } from 'element-plus'
|
||||||
import { useStore } from '@/store'
|
|
||||||
import { domainFormat } from '@/utils/validator'
|
import { domainFormat } from '@/utils/validator'
|
||||||
import { ACTION_TYPES } from '@/store/Login'
|
import { detector, OAuth } from 'megalodon'
|
||||||
|
import { MyWindow } from '~/src/types/global'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { LocalServer } from '~/src/types/localServer'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'login-form',
|
name: 'login-form',
|
||||||
setup() {
|
setup() {
|
||||||
const space = 'Login'
|
|
||||||
const store = useStore()
|
|
||||||
const i18n = useI18next()
|
const i18n = useI18next()
|
||||||
|
const router = useRouter()
|
||||||
|
const win = (window as any) as MyWindow
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
domainName: ''
|
domainName: ''
|
||||||
})
|
})
|
||||||
const loginFormRef = ref<FormInstance>()
|
const loginFormRef = ref<FormInstance>()
|
||||||
|
const domain = ref<string>('')
|
||||||
|
const searching = ref<boolean>(false)
|
||||||
|
const allowLogin = computed(() => domain.value && form.domainName == domain.value)
|
||||||
|
const sns = ref<'mastodon' | 'pleroma' | 'misskey'>('mastodon')
|
||||||
|
|
||||||
const selectedInstance = computed(() => store.state.Login.domain)
|
|
||||||
const searching = computed(() => store.state.Login.searching)
|
|
||||||
const allowLogin = computed(() => selectedInstance.value && form.domainName === selectedInstance.value)
|
|
||||||
const rules = reactive<FormRules>({
|
const rules = reactive<FormRules>({
|
||||||
domainName: [
|
domainName: [
|
||||||
{
|
{
|
||||||
|
@ -81,8 +84,20 @@ export default defineComponent({
|
||||||
background: 'rgba(0, 0, 0, 0.7)'
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
await store.dispatch(`${space}/${ACTION_TYPES.ADD_SERVER}`)
|
const server: LocalServer = await win.ipcRenderer.invoke('add-server', domain.value)
|
||||||
await store.dispatch(`${space}/${ACTION_TYPES.ADD_APP}`)
|
const appData: OAuth.AppData = await win.ipcRenderer.invoke('add-app', `https://${domain.value}`)
|
||||||
|
router.push({
|
||||||
|
path: '/login/authorize',
|
||||||
|
query: {
|
||||||
|
server_id: server.id,
|
||||||
|
base_url: server.baseURL,
|
||||||
|
client_id: appData.client_id,
|
||||||
|
client_secret: appData.client_secret,
|
||||||
|
session_token: appData.session_token,
|
||||||
|
sns: sns.value,
|
||||||
|
url: appData.url
|
||||||
|
}
|
||||||
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: i18n.t('message.authorize_url_error'),
|
message: i18n.t('message.authorize_url_error'),
|
||||||
|
@ -96,27 +111,31 @@ export default defineComponent({
|
||||||
|
|
||||||
const confirm = async (formEl: FormInstance | undefined) => {
|
const confirm = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return
|
if (!formEl) return
|
||||||
await formEl.validate(valid => {
|
await formEl.validate(async valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
return store
|
searching.value = true
|
||||||
.dispatch(`${space}/${ACTION_TYPES.CONFIRM_INSTANCE}`, form.domainName)
|
try {
|
||||||
.then(() => {
|
const cleanDomain = form.domainName.trim()
|
||||||
|
sns.value = await detector(`https://${cleanDomain}`)
|
||||||
|
domain.value = cleanDomain
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: i18n.t('message.domain_confirmed', {
|
message: i18n.t('message.domain_confirmed', {
|
||||||
domain: form.domainName
|
domain: cleanDomain
|
||||||
}),
|
}),
|
||||||
type: 'success'
|
type: 'success'
|
||||||
})
|
})
|
||||||
})
|
} catch (err) {
|
||||||
.catch(err => {
|
console.error(err)
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: i18n.t('message.domain_doesnt_exist', {
|
message: i18n.t('message.domain_doesnt_exist', {
|
||||||
domain: form.domainName
|
domain: form.domainName
|
||||||
}),
|
}),
|
||||||
type: 'error'
|
type: 'error'
|
||||||
})
|
})
|
||||||
console.error(err)
|
} finally {
|
||||||
})
|
searching.value = false
|
||||||
|
}
|
||||||
|
return true
|
||||||
} else {
|
} else {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: i18n.t('validation.login.domain_format'),
|
message: i18n.t('validation.login.domain_format'),
|
||||||
|
|
|
@ -153,7 +153,7 @@ export default defineComponent({
|
||||||
|
|
||||||
const removeAllAssociations = () => {
|
const removeAllAssociations = () => {
|
||||||
store.dispatch(`${space}/${ACTION_TYPES.REMOVE_ALL_ACCOUNTS}`).then(() => {
|
store.dispatch(`${space}/${ACTION_TYPES.REMOVE_ALL_ACCOUNTS}`).then(() => {
|
||||||
router.push('/login')
|
router.push('/login/form')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
|
||||||
import Login from '@/components/Login.vue'
|
import Login from '@/components/Login.vue'
|
||||||
|
import LoginForm from '@/components/Login/LoginForm.vue'
|
||||||
|
import Authorize from '@/components/Login/Authorize.vue'
|
||||||
import Preferences from '@/components/Preferences.vue'
|
import Preferences from '@/components/Preferences.vue'
|
||||||
import PreferencesGeneral from '@/components/Preferences/General.vue'
|
import PreferencesGeneral from '@/components/Preferences/General.vue'
|
||||||
import PreferencesAppearance from '@/components/Preferences/Appearance.vue'
|
import PreferencesAppearance from '@/components/Preferences/Appearance.vue'
|
||||||
|
@ -34,9 +36,21 @@ import TimelineSpaceContentsBookmarks from '@/components/TimelineSpace/Contents/
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login/',
|
||||||
name: 'login',
|
name: 'login',
|
||||||
component: Login
|
component: Login,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'form',
|
||||||
|
name: 'login-form',
|
||||||
|
component: LoginForm
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'authorize',
|
||||||
|
name: 'authorize',
|
||||||
|
component: Authorize
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/preferences/',
|
path: '/preferences/',
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
import { Module, MutationTree, ActionTree } from 'vuex'
|
|
||||||
import { detector } from 'megalodon'
|
|
||||||
import { RootState } from '@/store'
|
|
||||||
import { MyWindow } from '~/src/types/global'
|
|
||||||
import { LocalServer } from '~src/types/localServer'
|
|
||||||
import { OAuth } from 'megalodon'
|
|
||||||
import { LocalAccount } from '~src/types/localAccount'
|
|
||||||
import { toRaw } from 'vue'
|
|
||||||
|
|
||||||
const win = (window as any) as MyWindow
|
|
||||||
|
|
||||||
export type LoginState = {
|
|
||||||
domain: string | null
|
|
||||||
searching: boolean
|
|
||||||
server: LocalServer | null
|
|
||||||
appData: OAuth.AppData | null
|
|
||||||
sns: 'mastodon' | 'pleroma' | 'misskey'
|
|
||||||
}
|
|
||||||
|
|
||||||
const state = (): LoginState => ({
|
|
||||||
domain: null,
|
|
||||||
searching: false,
|
|
||||||
server: null,
|
|
||||||
appData: null,
|
|
||||||
sns: 'mastodon'
|
|
||||||
})
|
|
||||||
|
|
||||||
export const MUTATION_TYPES = {
|
|
||||||
CHANGE_DOMAIN: 'changeDomain',
|
|
||||||
CHANGE_SEARCHING: 'changeSearching',
|
|
||||||
CHANGE_SERVER: 'changeServer',
|
|
||||||
CHANGE_APP_DATA: 'changeAppData',
|
|
||||||
CHANGE_SNS: 'changeSNS'
|
|
||||||
}
|
|
||||||
|
|
||||||
const mutations: MutationTree<LoginState> = {
|
|
||||||
[MUTATION_TYPES.CHANGE_DOMAIN]: (state: LoginState, instance: string | null) => {
|
|
||||||
state.domain = instance
|
|
||||||
},
|
|
||||||
[MUTATION_TYPES.CHANGE_SEARCHING]: (state: LoginState, searching: boolean) => {
|
|
||||||
state.searching = searching
|
|
||||||
},
|
|
||||||
[MUTATION_TYPES.CHANGE_SERVER]: (state: LoginState, server: LocalServer | null) => {
|
|
||||||
state.server = server
|
|
||||||
},
|
|
||||||
[MUTATION_TYPES.CHANGE_APP_DATA]: (state: LoginState, appData: OAuth.AppData | null) => {
|
|
||||||
state.appData = appData
|
|
||||||
},
|
|
||||||
[MUTATION_TYPES.CHANGE_SNS]: (state: LoginState, sns: 'mastodon' | 'pleroma' | 'misskey') => {
|
|
||||||
state.sns = sns
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ACTION_TYPES = {
|
|
||||||
ADD_SERVER: 'addServer',
|
|
||||||
ADD_APP: 'addApp',
|
|
||||||
AUTHORIZE: 'authorize',
|
|
||||||
PAGE_BACK: 'pageBack',
|
|
||||||
CONFIRM_INSTANCE: 'confirmInstance'
|
|
||||||
}
|
|
||||||
|
|
||||||
const actions: ActionTree<LoginState, RootState> = {
|
|
||||||
[ACTION_TYPES.ADD_SERVER]: async ({ state, commit }): Promise<LocalServer> => {
|
|
||||||
const server = await win.ipcRenderer.invoke('add-server', state.domain)
|
|
||||||
commit(MUTATION_TYPES.CHANGE_SERVER, server)
|
|
||||||
return server
|
|
||||||
},
|
|
||||||
[ACTION_TYPES.ADD_APP]: async ({ state, commit }) => {
|
|
||||||
const appData = await win.ipcRenderer.invoke('add-app', `https://${state.domain}`)
|
|
||||||
commit(MUTATION_TYPES.CHANGE_APP_DATA, appData)
|
|
||||||
},
|
|
||||||
[ACTION_TYPES.AUTHORIZE]: async ({ state }, code: string): Promise<number> => {
|
|
||||||
const localAccount: LocalAccount = await win.ipcRenderer.invoke('authorize', {
|
|
||||||
server: toRaw(state.server),
|
|
||||||
appData: toRaw(state.appData),
|
|
||||||
code
|
|
||||||
})
|
|
||||||
return localAccount.id
|
|
||||||
},
|
|
||||||
[ACTION_TYPES.PAGE_BACK]: ({ commit }) => {
|
|
||||||
commit(MUTATION_TYPES.CHANGE_DOMAIN, null)
|
|
||||||
commit(MUTATION_TYPES.CHANGE_SERVER, null)
|
|
||||||
commit(MUTATION_TYPES.CHANGE_APP_DATA, null)
|
|
||||||
},
|
|
||||||
[ACTION_TYPES.CONFIRM_INSTANCE]: async ({ commit }, domain: string): Promise<boolean> => {
|
|
||||||
commit(MUTATION_TYPES.CHANGE_SEARCHING, true)
|
|
||||||
const cleanDomain = domain.trim()
|
|
||||||
try {
|
|
||||||
const sns = await detector(`https://${cleanDomain}`)
|
|
||||||
commit(MUTATION_TYPES.CHANGE_DOMAIN, cleanDomain)
|
|
||||||
commit(MUTATION_TYPES.CHANGE_SNS, sns)
|
|
||||||
} finally {
|
|
||||||
commit(MUTATION_TYPES.CHANGE_SEARCHING, false)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Login: Module<LoginState, RootState> = {
|
|
||||||
namespaced: true,
|
|
||||||
state: state,
|
|
||||||
mutations: mutations,
|
|
||||||
actions: actions
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Login
|
|
|
@ -4,7 +4,6 @@ import { InjectionKey } from 'vue'
|
||||||
|
|
||||||
import App, { AppState } from './App'
|
import App, { AppState } from './App'
|
||||||
import GlobalHeader, { GlobalHeaderState } from './GlobalHeader'
|
import GlobalHeader, { GlobalHeaderState } from './GlobalHeader'
|
||||||
import Login, { LoginState } from './Login'
|
|
||||||
import TimelineSpace, { TimelineSpaceModuleState } from './TimelineSpace'
|
import TimelineSpace, { TimelineSpaceModuleState } from './TimelineSpace'
|
||||||
import Preferences, { PreferencesModuleState } from './Preferences'
|
import Preferences, { PreferencesModuleState } from './Preferences'
|
||||||
import Settings, { SettingsModuleState } from './Settings'
|
import Settings, { SettingsModuleState } from './Settings'
|
||||||
|
@ -15,7 +14,6 @@ const win = (window as any) as MyWindow
|
||||||
export interface RootState {
|
export interface RootState {
|
||||||
App: AppState
|
App: AppState
|
||||||
GlobalHeader: GlobalHeaderState
|
GlobalHeader: GlobalHeaderState
|
||||||
Login: LoginState
|
|
||||||
TimelineSpace: TimelineSpaceModuleState
|
TimelineSpace: TimelineSpaceModuleState
|
||||||
Preferences: PreferencesModuleState
|
Preferences: PreferencesModuleState
|
||||||
Settings: SettingsModuleState
|
Settings: SettingsModuleState
|
||||||
|
@ -34,7 +32,6 @@ export default createStore({
|
||||||
modules: {
|
modules: {
|
||||||
App,
|
App,
|
||||||
GlobalHeader,
|
GlobalHeader,
|
||||||
Login,
|
|
||||||
TimelineSpace,
|
TimelineSpace,
|
||||||
Preferences,
|
Preferences,
|
||||||
Settings
|
Settings
|
||||||
|
|
Loading…
Reference in New Issue