From 35d5e7d649bdaecf57aefde44463fd0225c660d4 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 5 Jun 2020 15:54:09 -0500 Subject: [PATCH] SecurityForm: Revoke OAuth token --- app/soapbox/actions/auth.js | 15 +++++++++++++++ app/soapbox/features/security/index.js | 14 ++++++++++++-- app/soapbox/reducers/auth.js | 4 ++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/app/soapbox/actions/auth.js b/app/soapbox/actions/auth.js index b6bcd888c..5c884dfd1 100644 --- a/app/soapbox/actions/auth.js +++ b/app/soapbox/actions/auth.js @@ -27,6 +27,10 @@ export const FETCH_TOKENS_REQUEST = 'FETCH_TOKENS_REQUEST'; export const FETCH_TOKENS_SUCCESS = 'FETCH_TOKENS_SUCCESS'; export const FETCH_TOKENS_FAIL = 'FETCH_TOKENS_FAIL'; +export const REVOKE_TOKEN_REQUEST = 'REVOKE_TOKEN_REQUEST'; +export const REVOKE_TOKEN_SUCCESS = 'REVOKE_TOKEN_SUCCESS'; +export const REVOKE_TOKEN_FAIL = 'REVOKE_TOKEN_FAIL'; + const noOp = () => () => new Promise(f => f()); function createAppAndToken() { @@ -204,6 +208,17 @@ export function fetchOAuthTokens() { }; } +export function revokeOAuthToken(id) { + return (dispatch, getState) => { + dispatch({ type: REVOKE_TOKEN_REQUEST, id }); + return api(getState).delete(`/api/oauth_tokens/${id}`).then(response => { + dispatch({ type: REVOKE_TOKEN_SUCCESS, id }); + }).catch(error => { + dispatch({ type: REVOKE_TOKEN_FAIL, id }); + }); + }; +} + export function authAppCreated(app) { return { type: AUTH_APP_CREATED, diff --git a/app/soapbox/features/security/index.js b/app/soapbox/features/security/index.js index 2dc378ff6..bfbd98946 100644 --- a/app/soapbox/features/security/index.js +++ b/app/soapbox/features/security/index.js @@ -15,6 +15,7 @@ import { changeEmail, changePassword, fetchOAuthTokens, + revokeOAuthToken, } from 'soapbox/actions/auth'; import { showAlert } from 'soapbox/actions/alerts'; @@ -210,6 +211,12 @@ class AuthTokenList extends ImmutablePureComponent { tokens: ImmutablePropTypes.list, } + handleRevoke = id => { + return e => { + this.props.dispatch(revokeOAuthToken(id)); + }; + } + componentDidMount() { this.props.dispatch(fetchOAuthTokens()); } @@ -221,9 +228,12 @@ class AuthTokenList extends ImmutablePureComponent { {this.props.tokens.map((token, i) => (
{token.get('app_name')}
-
{token.get('id')}
{token.get('valid_until')}
-
+
+ +
))} diff --git a/app/soapbox/reducers/auth.js b/app/soapbox/reducers/auth.js index 35bf85559..5bd996f34 100644 --- a/app/soapbox/reducers/auth.js +++ b/app/soapbox/reducers/auth.js @@ -4,6 +4,7 @@ import { AUTH_APP_AUTHORIZED, AUTH_LOGGED_OUT, FETCH_TOKENS_SUCCESS, + REVOKE_TOKEN_SUCCESS, } from '../actions/auth'; import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; @@ -30,6 +31,9 @@ export default function auth(state = initialState, action) { return state.set('user', ImmutableMap()); case FETCH_TOKENS_SUCCESS: return state.set('tokens', fromJS(action.tokens)); + case REVOKE_TOKEN_SUCCESS: + const idx = state.get('tokens').findIndex(t => t.get('id') === action.id); + return state.deleteIn(['tokens', idx]); default: return state; }