aboutsummaryrefslogtreecommitdiff
path: root/src/services
diff options
context:
space:
mode:
Diffstat (limited to 'src/services')
-rw-r--r--src/services/api/api.service.js117
-rw-r--r--src/services/backend_interactor_service/backend_interactor_service.js15
-rw-r--r--src/services/entity_normalizer/entity_normalizer.service.js22
-rw-r--r--src/services/new_api/mfa.js38
-rw-r--r--src/services/new_api/oauth.js121
-rw-r--r--src/services/new_api/utils.js4
6 files changed, 249 insertions, 68 deletions
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index d6904d30..ab1fc0b2 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -1,7 +1,4 @@
/* 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'
const BLOCKS_IMPORT_URL = '/api/pleroma/blocks_import'
@@ -18,6 +15,15 @@ const ADMIN_USERS_URL = '/api/pleroma/admin/users'
const SUGGESTIONS_URL = '/api/v1/suggestions'
const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings'
+const MFA_SETTINGS_URL = '/api/pleroma/profile/mfa'
+const MFA_BACKUP_CODES_URL = '/api/pleroma/profile/mfa/backup_codes'
+
+const MFA_SETUP_OTP_URL = '/api/pleroma/profile/mfa/setup/totp'
+const MFA_CONFIRM_OTP_URL = '/api/pleroma/profile/mfa/confirm/totp'
+const MFA_DISABLE_OTP_URL = '/api/pleroma/profile/mfa/totp'
+
+const MASTODON_LOGIN_URL = '/api/v1/accounts/verify_credentials'
+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`
@@ -125,22 +131,16 @@ const updateAvatar = ({credentials, avatar}) => {
.then((data) => parseUser(data))
}
-const updateBg = ({credentials, params}) => {
- let url = BG_UPDATE_URL
-
+const updateBg = ({ credentials, background }) => {
const form = new FormData()
-
- each(params, (value, key) => {
- if (value) {
- form.append(key, value)
- }
- })
-
- return fetch(url, {
+ form.append('pleroma_background_image', background)
+ return fetch(MASTODON_PROFILE_UPDATE_URL, {
headers: authHeaders(credentials),
- method: 'POST',
+ method: 'PATCH',
body: form
- }).then((data) => data.json())
+ })
+ .then((data) => data.json())
+ .then((data) => parseUser(data))
}
const updateBanner = ({credentials, banner}) => {
@@ -177,19 +177,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: 'en_US',
+ 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())
@@ -513,8 +523,7 @@ const fetchPinnedStatuses = ({ id, credentials }) => {
}
const verifyCredentials = (user) => {
- return fetch(LOGIN_URL, {
- method: 'POST',
+ return fetch(MASTODON_LOGIN_URL, {
headers: authHeaders(user)
})
.then((response) => {
@@ -649,6 +658,51 @@ const changePassword = ({credentials, password, newPassword, newPasswordConfirma
.then((response) => response.json())
}
+const settingsMFA = ({credentials}) => {
+ return fetch(MFA_SETTINGS_URL, {
+ headers: authHeaders(credentials),
+ method: 'GET'
+ }).then((data) => data.json())
+}
+
+const mfaDisableOTP = ({credentials, password}) => {
+ const form = new FormData()
+
+ form.append('password', password)
+
+ return fetch(MFA_DISABLE_OTP_URL, {
+ body: form,
+ method: 'DELETE',
+ headers: authHeaders(credentials)
+ })
+ .then((response) => response.json())
+}
+
+const mfaConfirmOTP = ({credentials, password, token}) => {
+ const form = new FormData()
+
+ form.append('password', password)
+ form.append('code', token)
+
+ return fetch(MFA_CONFIRM_OTP_URL, {
+ body: form,
+ headers: authHeaders(credentials),
+ method: 'POST'
+ }).then((data) => data.json())
+}
+const mfaSetupOTP = ({credentials}) => {
+ return fetch(MFA_SETUP_OTP_URL, {
+ headers: authHeaders(credentials),
+ method: 'GET'
+ }).then((data) => data.json())
+}
+const generateMfaBackupCodes = ({credentials}) => {
+ return fetch(MFA_BACKUP_CODES_URL, {
+ headers: authHeaders(credentials),
+ method: 'GET'
+ }).then((data) => data.json())
+}
+
const fetchMutes = ({credentials}) => {
return promisedRequest({ url: MASTODON_USER_MUTES_URL, credentials })
.then((users) => users.map(parseUser))
@@ -776,6 +830,11 @@ const apiService = {
importFollows,
deleteAccount,
changePassword,
+ settingsMFA,
+ mfaDisableOTP,
+ generateMfaBackupCodes,
+ mfaSetupOTP,
+ mfaConfirmOTP,
fetchFollowRequests,
approveUser,
denyUser,
diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js
index 36152429..8614a0f2 100644
--- a/src/services/backend_interactor_service/backend_interactor_service.js
+++ b/src/services/backend_interactor_service/backend_interactor_service.js
@@ -103,9 +103,9 @@ 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 updateBg = ({ background }) => apiService.updateBg({ credentials, background })
const updateBanner = ({banner}) => apiService.updateBanner({credentials, banner})
const updateProfile = ({params}) => apiService.updateProfile({credentials, params})
@@ -116,6 +116,12 @@ const backendInteractorService = (credentials) => {
const deleteAccount = ({password}) => apiService.deleteAccount({credentials, password})
const changePassword = ({password, newPassword, newPasswordConfirmation}) => apiService.changePassword({credentials, password, newPassword, newPasswordConfirmation})
+ const fetchSettingsMFA = () => apiService.settingsMFA({credentials})
+ const generateMfaBackupCodes = () => apiService.generateMfaBackupCodes({credentials})
+ const mfaSetupOTP = () => apiService.mfaSetupOTP({credentials})
+ const mfaConfirmOTP = ({password, token}) => apiService.mfaConfirmOTP({credentials, password, token})
+ const mfaDisableOTP = ({password}) => apiService.mfaDisableOTP({credentials, password})
+
const fetchFavoritedByUsers = (id) => apiService.fetchFavoritedByUsers({id})
const fetchRebloggedByUsers = (id) => apiService.fetchRebloggedByUsers({id})
const reportUser = (params) => apiService.reportUser({credentials, ...params})
@@ -166,6 +172,11 @@ const backendInteractorService = (credentials) => {
importFollows,
deleteAccount,
changePassword,
+ fetchSettingsMFA,
+ generateMfaBackupCodes,
+ mfaSetupOTP,
+ mfaConfirmOTP,
+ mfaDisableOTP,
fetchFollowRequests,
approveUser,
denyUser,
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 1f03058d..cdce1538 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -60,6 +60,9 @@ export const parseUser = (data) => {
if (data.pleroma) {
const relationship = data.pleroma.relationship
+ output.background_image = data.pleroma.background_image
+ output.token = data.pleroma.chat_token
+
if (relationship) {
output.follows_you = relationship.followed_by
output.following = relationship.following
@@ -71,6 +74,23 @@ export const parseUser = (data) => {
moderator: data.pleroma.is_moderator,
admin: data.pleroma.is_admin
}
+ // TODO: Clean up in UI? This is duplication from what BE does for qvitterapi
+ if (output.rights.admin) {
+ output.role = 'admin'
+ } else if (output.rights.moderator) {
+ output.role = 'moderator'
+ } else {
+ output.role = 'member'
+ }
+ }
+
+ if (data.source) {
+ output.description = data.source.note
+ output.default_scope = data.source.privacy
+ if (data.source.pleroma) {
+ output.no_rich_text = data.source.pleroma.no_rich_text
+ output.show_role = data.source.pleroma.show_role
+ }
}
// TODO: handle is_local
@@ -105,8 +125,6 @@ export const parseUser = (data) => {
output.muted = data.muted
- // QVITTER ONLY FOR NOW
- // Really only applies to logged in user, really.. I THINK
if (data.rights) {
output.rights = {
moderator: data.rights.delete_others_notice,
diff --git a/src/services/new_api/mfa.js b/src/services/new_api/mfa.js
new file mode 100644
index 00000000..ddf90e6b
--- /dev/null
+++ b/src/services/new_api/mfa.js
@@ -0,0 +1,38 @@
+const verifyOTPCode = ({app, instance, mfaToken, code}) => {
+ const url = `${instance}/oauth/mfa/challenge`
+ const form = new window.FormData()
+
+ form.append('client_id', app.client_id)
+ form.append('client_secret', app.client_secret)
+ form.append('mfa_token', mfaToken)
+ form.append('code', code)
+ form.append('challenge_type', 'totp')
+
+ return window.fetch(url, {
+ method: 'POST',
+ body: form
+ }).then((data) => data.json())
+}
+
+const verifyRecoveryCode = ({app, instance, mfaToken, code}) => {
+ const url = `${instance}/oauth/mfa/challenge`
+ const form = new window.FormData()
+
+ form.append('client_id', app.client_id)
+ form.append('client_secret', app.client_secret)
+ form.append('mfa_token', mfaToken)
+ form.append('code', code)
+ form.append('challenge_type', 'recovery')
+
+ return window.fetch(url, {
+ method: 'POST',
+ body: form
+ }).then((data) => data.json())
+}
+
+const mfa = {
+ verifyOTPCode,
+ verifyRecoveryCode
+}
+
+export default mfa
diff --git a/src/services/new_api/oauth.js b/src/services/new_api/oauth.js
index 9e656507..030e9980 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 login = ({ instance, clientId }) => {
+ const data = {
+ response_type: 'code',
+ client_id: clientId,
+ redirect_uri: 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 dataString = reduce(data, (acc, v, k) => {
+ const encoded = `${k}=${encodeURIComponent(v)}`
+ if (!acc) {
+ return encoded
+ } else {
+ return `${acc}&${encoded}`
+ }
+ }, false)
- // Do the redirect...
- const url = `${args.instance}/oauth/authorize?${dataString}`
+ // Do the redirect...
+ const url = `${instance}/oauth/authorize?${dataString}`
- window.location.href = url
- })
+ 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,53 @@ 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())
+}
+const verifyOTPCode = ({app, instance, mfaToken, code}) => {
+ const url = `${instance}/oauth/mfa/challenge`
+ const form = new window.FormData()
+
+ form.append('client_id', app.client_id)
+ form.append('client_secret', app.client_secret)
+ form.append('mfa_token', mfaToken)
+ form.append('code', code)
+ form.append('challenge_type', 'totp')
+
+ return window.fetch(url, {
+ method: 'POST',
+ body: form
+ }).then((data) => data.json())
+}
+
+const verifyRecoveryCode = ({app, instance, mfaToken, code}) => {
+ const url = `${instance}/oauth/mfa/challenge`
+ const form = new window.FormData()
+
+ form.append('client_id', app.client_id)
+ form.append('client_secret', app.client_secret)
+ form.append('mfa_token', mfaToken)
+ form.append('code', code)
+ form.append('challenge_type', 'recovery')
+
+ return window.fetch(url, {
+ method: 'POST',
+ body: form
}).then((data) => data.json())
}
@@ -76,7 +129,9 @@ const oauth = {
login,
getToken,
getTokenWithCredentials,
- getOrCreateApp
+ getOrCreateApp,
+ verifyOTPCode,
+ verifyRecoveryCode
}
export default oauth
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 {}
}