aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Jameson <me@hjkos.com>2019-05-22 19:13:41 +0300
committerHenry Jameson <me@hjkos.com>2019-05-22 19:13:41 +0300
commite7a2a7267dbd8a4ee3d266d22249459d028569d6 (patch)
tree36bf31c489e26ae9adebdca8ee75f49c16688eb0
parent233506f6c1b0b16ca62c557ae6eca4a585e28a2c (diff)
Proper clientId/secret/token caching, MastoAPI registration
-rw-r--r--.eslintrc.js3
-rw-r--r--src/boot/after_store.js15
-rw-r--r--src/components/login_form/login_form.js16
-rw-r--r--src/components/oauth_callback/oauth_callback.js4
-rw-r--r--src/modules/oauth.js21
-rw-r--r--src/modules/users.js37
-rw-r--r--src/services/api/api.service.js34
-rw-r--r--src/services/backend_interactor_service/backend_interactor_service.js2
-rw-r--r--src/services/new_api/oauth.js88
-rw-r--r--src/services/new_api/utils.js4
10 files changed, 135 insertions, 89 deletions
diff --git a/.eslintrc.js b/.eslintrc.js
index b526df67..7d090208 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -31,8 +31,7 @@ module.exports = {
'vue/require-prop-types': 1,
'vue/no-use-v-if-with-v-for': 1,
'indent': 1,
- 'import/first': 1, // ????
- 'import-first': 1,
+ 'import/first': 1,
'object-curly-spacing': 1,
'prefer-promise-reject-errors': 1,
'eol-last': 1,
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 603de348..caaede59 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -3,6 +3,8 @@ import VueRouter from 'vue-router'
import routes from './routes'
import App from '../App.vue'
import { windowWidth } from '../services/window_utils/window_utils'
+import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
+import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
const getStatusnetConfig = async ({ store }) => {
try {
@@ -188,6 +190,17 @@ const getCustomEmoji = async ({ store }) => {
}
}
+const getAppSecret = async ({ store }) => {
+ const { state, commit } = store
+ const { oauth, instance } = state
+ return getOrCreateApp({ ...oauth, instance: instance.server, commit })
+ .then((app) => getClientToken({ ...app, instance: instance.server }))
+ .then((token) => {
+ commit('setClientToken', token.access_token)
+ commit('setBackendInteractor', backendInteractorService(store.getters.getToken()))
+ })
+}
+
const getNodeInfo = async ({ store }) => {
try {
const res = await window.fetch('/nodeinfo/2.0.json')
@@ -228,7 +241,7 @@ const setConfig = async ({ store }) => {
const apiConfig = configInfos[0]
const staticConfig = configInfos[1]
- await setSettings({ store, apiConfig, staticConfig })
+ await setSettings({ store, apiConfig, staticConfig }).then(getAppSecret({ store }))
}
const checkOAuthToken = async ({ store }) => {
diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js
index dc917e47..0097e18a 100644
--- a/src/components/login_form/login_form.js
+++ b/src/components/login_form/login_form.js
@@ -11,22 +11,26 @@ const LoginForm = {
},
methods: {
oAuthLogin () {
- oauthApi.login({
- oauth: this.$store.state.oauth,
+ const data = {
+ ...this.$store.state.oauth,
instance: this.$store.state.instance.server,
commit: this.$store.commit
- })
+ }
+
+ oauthApi.getOrCreateApp(data)
+ .then((app) => { oauthApi.login({ ...app, ...data }) })
},
submit () {
const data = {
- oauth: this.$store.state.oauth,
- instance: this.$store.state.instance.server
+ ...this.$store.state.oauth,
+ instance: this.$store.state.instance.server,
+ commit: this.$store.commit
}
this.clearError()
oauthApi.getOrCreateApp(data).then((app) => {
oauthApi.getTokenWithCredentials(
{
- app,
+ ...app,
instance: data.instance,
username: this.user.username,
password: this.user.password
diff --git a/src/components/oauth_callback/oauth_callback.js b/src/components/oauth_callback/oauth_callback.js
index e3d45ee1..48ddd10d 100644
--- a/src/components/oauth_callback/oauth_callback.js
+++ b/src/components/oauth_callback/oauth_callback.js
@@ -5,13 +5,13 @@ const oac = {
mounted () {
if (this.code) {
oauth.getToken({
- app: this.$store.state.oauth,
+ ...this.$store.state.oauth,
instance: this.$store.state.instance.server,
code: this.code
}).then((result) => {
this.$store.commit('setToken', result.access_token)
this.$store.dispatch('loginUser', result.access_token)
- this.$router.push({name: 'friends'})
+ this.$router.push({ name: 'friends' })
})
}
}
diff --git a/src/modules/oauth.js b/src/modules/oauth.js
index 144ff830..242e29c3 100644
--- a/src/modules/oauth.js
+++ b/src/modules/oauth.js
@@ -1,17 +1,26 @@
const oauth = {
state: {
- client_id: false,
- client_secret: false,
- token: false
+ clientId: false,
+ clientSecret: false,
+ token: false,
+ clientToken: false
},
mutations: {
- setClientData (state, data) {
- state.client_id = data.client_id
- state.client_secret = data.client_secret
+ setClientData (state, { clientId, clientSecret }) {
+ state.clientId = clientId
+ state.clientSecret = clientSecret
+ },
+ setClientToken (state, token) {
+ state.clientToken = token
},
setToken (state, token) {
state.token = token
}
+ },
+ getters: {
+ getToken: state => () => {
+ return state.token || state.clientToken
+ }
}
}
diff --git a/src/modules/users.js b/src/modules/users.js
index e72a657c..739b8b92 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -3,7 +3,6 @@ import userSearchApi from '../services/new_api/user_search.js'
import { compact, map, each, merge, last, concat, uniq } from 'lodash'
import { set } from 'vue'
import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js'
-import oauthApi from '../services/new_api/oauth'
import { humanizeErrors } from './errors'
// TODO: Unify with mergeOrAdd in statuses.js
@@ -368,31 +367,21 @@ const users = {
let rootState = store.rootState
- let response = await rootState.api.backendInteractor.register(userInfo)
- if (response.ok) {
- const data = {
- oauth: rootState.oauth,
- instance: rootState.instance.server
- }
- let app = await oauthApi.getOrCreateApp(data)
- let result = await oauthApi.getTokenWithCredentials({
- app,
- instance: data.instance,
- username: userInfo.username,
- password: userInfo.password
- })
+ try {
+ let data = await rootState.api.backendInteractor.register(userInfo)
store.commit('signUpSuccess')
- store.commit('setToken', result.access_token)
- store.dispatch('loginUser', result.access_token)
- } else {
- const data = await response.json()
- let errors = JSON.parse(data.error)
+ store.commit('setToken', data.access_token)
+ store.dispatch('loginUser', data.access_token)
+ } catch (e) {
+ let errors = e.message
// replace ap_id with username
- if (errors.ap_id) {
- errors.username = errors.ap_id
- delete errors.ap_id
+ if (typeof errors === 'object') {
+ if (errors.ap_id) {
+ errors.username = errors.ap_id
+ delete errors.ap_id
+ }
+ errors = humanizeErrors(errors)
}
- errors = humanizeErrors(errors)
store.commit('signUpFailure', errors)
throw Error(errors)
}
@@ -406,7 +395,7 @@ const users = {
store.dispatch('disconnectFromChat')
store.commit('setToken', false)
store.dispatch('stopFetching', 'friends')
- store.commit('setBackendInteractor', backendInteractorService())
+ store.commit('setBackendInteractor', backendInteractorService(store.getters.getToken()))
store.dispatch('stopFetching', 'notifications')
store.commit('clearNotifications')
store.commit('resetStatuses')
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index c67eccf1..559eb25d 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -1,6 +1,5 @@
/* eslint-env browser */
const LOGIN_URL = '/api/account/verify_credentials.json'
-const REGISTRATION_URL = '/api/account/register.json'
const BG_UPDATE_URL = '/api/qvitter/update_background_image.json'
const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json'
const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json'
@@ -17,6 +16,7 @@ const ACTIVATION_STATUS_URL = screenName => `/api/pleroma/admin/users/${screenNa
const ADMIN_USERS_URL = '/api/pleroma/admin/users'
const SUGGESTIONS_URL = '/api/v1/suggestions'
+const MASTODON_REGISTRATION_URL = '/api/v1/accounts'
const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites'
const MASTODON_USER_NOTIFICATIONS_URL = '/api/v1/notifications'
const MASTODON_FAVORITE_URL = id => `/api/v1/statuses/${id}/favourite`
@@ -161,19 +161,29 @@ const updateProfile = ({credentials, params}) => {
// homepage
// location
// token
-const register = (params) => {
- const form = new FormData()
-
- each(params, (value, key) => {
- if (value) {
- form.append(key, value)
- }
- })
-
- return fetch(REGISTRATION_URL, {
+const register = ({ params, credentials }) => {
+ const { nickname, ...rest } = params
+ return fetch(MASTODON_REGISTRATION_URL, {
method: 'POST',
- body: form
+ headers: {
+ ...authHeaders(credentials),
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ nickname,
+ locale: 'xx_XX',
+ agreement: true,
+ ...rest
+ })
})
+ .then((response) => [response.ok, response])
+ .then(([ok, response]) => {
+ if (ok) {
+ return response.json()
+ } else {
+ return response.json().then((error) => { throw new Error(error) })
+ }
+ })
}
const getCaptcha = () => fetch('/api/pleroma/captcha').then(resp => resp.json())
diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js
index 639bcabc..3d6edfc3 100644
--- a/src/services/backend_interactor_service/backend_interactor_service.js
+++ b/src/services/backend_interactor_service/backend_interactor_service.js
@@ -99,7 +99,7 @@ const backendInteractorService = (credentials) => {
const unpinOwnStatus = (id) => apiService.unpinOwnStatus({credentials, id})
const getCaptcha = () => apiService.getCaptcha()
- const register = (params) => apiService.register(params)
+ const register = (params) => apiService.register({ credentials, params })
const updateAvatar = ({avatar}) => apiService.updateAvatar({credentials, avatar})
const updateBg = ({params}) => apiService.updateBg({credentials, params})
const updateBanner = ({banner}) => apiService.updateBanner({credentials, banner})
diff --git a/src/services/new_api/oauth.js b/src/services/new_api/oauth.js
index 9e656507..4730427d 100644
--- a/src/services/new_api/oauth.js
+++ b/src/services/new_api/oauth.js
@@ -1,51 +1,57 @@
-import {reduce} from 'lodash'
+import { reduce } from 'lodash'
+
+const REDIRECT_URI = `${window.location.origin}/oauth-callback`
+
+export const getOrCreateApp = ({ clientId, clientSecret, instance, commit }) => {
+ if (clientId && clientSecret) {
+ return Promise.resolve({ clientId, clientSecret })
+ }
-const getOrCreateApp = ({oauth, instance}) => {
const url = `${instance}/api/v1/apps`
const form = new window.FormData()
- form.append('client_name', `PleromaFE_${Math.random()}`)
- form.append('redirect_uris', `${window.location.origin}/oauth-callback`)
+ form.append('client_name', `PleromaFE_${window.___pleromafe_commit_hash}_${(new Date()).toISOString()}`)
+ form.append('redirect_uris', REDIRECT_URI)
form.append('scopes', 'read write follow')
return window.fetch(url, {
method: 'POST',
body: form
- }).then((data) => data.json())
+ })
+ .then((data) => data.json())
+ .then((app) => ({ clientId: app.client_id, clientSecret: app.client_secret }))
+ .then((app) => commit('setClientData', app) || app)
}
-const login = (args) => {
- getOrCreateApp(args).then((app) => {
- args.commit('setClientData', app)
-
- const data = {
- response_type: 'code',
- client_id: app.client_id,
- redirect_uri: app.redirect_uri,
- scope: 'read write follow'
- }
- const dataString = reduce(data, (acc, v, k) => {
- const encoded = `${k}=${encodeURIComponent(v)}`
- if (!acc) {
- return encoded
- } else {
- return `${acc}&${encoded}`
- }
- }, false)
+const login = ({ instance, clientId }) => {
+ const data = {
+ response_type: 'code',
+ client_id: clientId,
+ redirect_uri: REDIRECT_URI,
+ scope: 'read write follow'
+ }
- // Do the redirect...
- const url = `${args.instance}/oauth/authorize?${dataString}`
+ const dataString = reduce(data, (acc, v, k) => {
+ const encoded = `${k}=${encodeURIComponent(v)}`
+ if (!acc) {
+ return encoded
+ } else {
+ return `${acc}&${encoded}`
+ }
+ }, false)
- window.location.href = url
- })
+ // Do the redirect...
+ const url = `${instance}/oauth/authorize?${dataString}`
+
+ window.location.href = url
}
-const getTokenWithCredentials = ({app, instance, username, password}) => {
+const getTokenWithCredentials = ({ clientId, clientSecret, instance, username, password }) => {
const url = `${instance}/oauth/token`
const form = new window.FormData()
- form.append('client_id', app.client_id)
- form.append('client_secret', app.client_secret)
+ form.append('client_id', clientId)
+ form.append('client_secret', clientSecret)
form.append('grant_type', 'password')
form.append('username', username)
form.append('password', password)
@@ -56,12 +62,12 @@ const getTokenWithCredentials = ({app, instance, username, password}) => {
}).then((data) => data.json())
}
-const getToken = ({app, instance, code}) => {
+const getToken = ({ clientId, clientSecret, instance, code }) => {
const url = `${instance}/oauth/token`
const form = new window.FormData()
- form.append('client_id', app.client_id)
- form.append('client_secret', app.client_secret)
+ form.append('client_id', clientId)
+ form.append('client_secret', clientSecret)
form.append('grant_type', 'authorization_code')
form.append('code', code)
form.append('redirect_uri', `${window.location.origin}/oauth-callback`)
@@ -69,6 +75,22 @@ const getToken = ({app, instance, code}) => {
return window.fetch(url, {
method: 'POST',
body: form
+ })
+ .then((data) => data.json())
+}
+
+export const getClientToken = ({ clientId, clientSecret, instance }) => {
+ const url = `${instance}/oauth/token`
+ const form = new window.FormData()
+
+ form.append('client_id', clientId)
+ form.append('client_secret', clientSecret)
+ form.append('grant_type', 'client_credentials')
+ form.append('redirect_uri', `${window.location.origin}/oauth-callback`)
+
+ return window.fetch(url, {
+ method: 'POST',
+ body: form
}).then((data) => data.json())
}
diff --git a/src/services/new_api/utils.js b/src/services/new_api/utils.js
index 078f392f..6696573b 100644
--- a/src/services/new_api/utils.js
+++ b/src/services/new_api/utils.js
@@ -5,9 +5,9 @@ const queryParams = (params) => {
}
const headers = (store) => {
- const accessToken = store.state.oauth.token
+ const accessToken = store.getters.getToken()
if (accessToken) {
- return {'Authorization': `Bearer ${accessToken}`}
+ return { 'Authorization': `Bearer ${accessToken}` }
} else {
return {}
}