Merge pull request #1087 from h3poteto/iss-1076

closes #1076 Check instance API before request host-meta when confirm instance
This commit is contained in:
AkiraFukushima 2019-11-07 22:50:53 +09:00 committed by GitHub
commit 3709deb5ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 15 deletions

View File

@ -1,10 +1,10 @@
import { createLocalVue } from '@vue/test-utils' import { createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex' import Vuex from 'vuex'
import { ipcMain } from '~/spec/mock/electron' import { ipcMain } from '~/spec/mock/electron'
import axios from 'axios' import Mastodon, { Instance, Response } from 'megalodon'
import Login, { LoginState } from '@/store/Login' import Login, { LoginState } from '@/store/Login'
jest.mock('axios') jest.mock('megalodon')
const state = (): LoginState => { const state = (): LoginState => {
return { return {
@ -78,14 +78,53 @@ describe('Login', () => {
// Provide Promise.resolve for finally keywrod. // Provide Promise.resolve for finally keywrod.
// https://github.com/facebook/jest/issues/6552 // https://github.com/facebook/jest/issues/6552
// https://github.com/kulshekhar/ts-jest/issues/828 // https://github.com/kulshekhar/ts-jest/issues/828
const mockedAxios = axios as any const mockedClient = Mastodon as any
const res: Promise<{}> = new Promise<{}>(resolve => { const instance: Promise<Response<Instance>> = new Promise<Response<Instance>>(resolve => {
const res: Response<Instance> = {
data: {
uri: 'http://example.com',
title: 'test-mastodon',
description: 'description',
email: 'hoge@example.com',
version: '1.0.0',
thumbnail: null,
urls: {
streaming_api: 'http://example.com'
},
stats: {
user_count: 1,
status_count: 10,
domain_count: 10
},
languages: ['en'],
contact_account: null
} as Instance,
status: 200,
statusText: '200',
headers: null
}
resolve(res)
})
mockedClient.get.mockImplementation(() => instance)
const result = await store.dispatch('Login/confirmInstance', 'pleroma.io')
expect(result).toEqual(true)
expect(store.state.Login.selectedInstance).toEqual('pleroma.io')
})
it('should failover host-meta', async () => {
const mockedClient = Mastodon as any
// @ts-ignore
const instance: Promise<any> = new Promise<any>((resolve, reject) => {
const err = new Error('err')
reject(err)
})
const hostMeta: Promise<{}> = new Promise<{}>(resolve => {
resolve({ resolve({
data: data:
'<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="https://pleroma.io/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /></XRD>' '<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="https://pleroma.io/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /></XRD>'
}) })
}) })
mockedAxios.get.mockImplementation(() => res) mockedClient.get.mockImplementationOnce(() => instance).mockImplementationOnce(() => hostMeta)
const result = await store.dispatch('Login/confirmInstance', 'pleroma.io') const result = await store.dispatch('Login/confirmInstance', 'pleroma.io')
expect(result).toEqual(true) expect(result).toEqual(true)
expect(store.state.Login.selectedInstance).toEqual('pleroma.io') expect(store.state.Login.selectedInstance).toEqual('pleroma.io')

View File

@ -1,5 +1,5 @@
import { ipcRenderer } from 'electron' import { ipcRenderer } from 'electron'
import Mastodon from 'megalodon' import Mastodon, { Instance } from 'megalodon'
import { Module, MutationTree, ActionTree } from 'vuex' import { Module, MutationTree, ActionTree } from 'vuex'
import { RootState } from '@/store' import { RootState } from '@/store'
@ -46,17 +46,24 @@ const actions: ActionTree<LoginState, RootState> = {
}, },
confirmInstance: async ({ commit, rootState }, domain: string): Promise<boolean> => { confirmInstance: async ({ commit, rootState }, domain: string): Promise<boolean> => {
commit(MUTATION_TYPES.CHANGE_SEARCHING, true) commit(MUTATION_TYPES.CHANGE_SEARCHING, true)
try {
await Mastodon.get<Instance>('/api/v1/instance', {}, `https://${domain}`, rootState.App.proxyConfiguration)
commit(MUTATION_TYPES.CHANGE_SEARCHING, false)
} catch (err) {
// https://gist.github.com/okapies/60d62d0df0163bbfb4ab09c1766558e8 // https://gist.github.com/okapies/60d62d0df0163bbfb4ab09c1766558e8
// Check /.well-known/host-meta to confirm mastodon instance. // Check /.well-known/host-meta to confirm mastodon instance.
const res = await Mastodon.get<any>('/.well-known/host-meta', {}, `https://${domain}`, rootState.App.proxyConfiguration).finally(() => { const res = await Mastodon.get<any>('/.well-known/host-meta', {}, `https://${domain}`, rootState.App.proxyConfiguration).finally(
() => {
commit(MUTATION_TYPES.CHANGE_SEARCHING, false) commit(MUTATION_TYPES.CHANGE_SEARCHING, false)
}) }
)
const parser = new DOMParser() const parser = new DOMParser()
const dom = parser.parseFromString(res.data, 'text/xml') const dom = parser.parseFromString(res.data, 'text/xml')
const link = dom.getElementsByTagName('Link')[0].outerHTML const link = dom.getElementsByTagName('Link')[0].outerHTML
if (!link.includes(`https://${domain}/.well-known/webfinger`)) { if (!link.includes(`https://${domain}/.well-known/webfinger`)) {
throw new Error('domain is not activity pub') throw new Error('domain is not activity pub')
} }
}
commit(MUTATION_TYPES.CHANGE_INSTANCE, domain) commit(MUTATION_TYPES.CHANGE_INSTANCE, domain)
return true return true
} }