mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 14:47:53 +01:00
reset the ApiToken on password changes/resets (#15433)
* reset the ApiToken on password changes/resets * fix/add tests * fix(typo): test grammar * update new API Token Strings, removed unused one --------- Co-authored-by: Kalista Payne <sabrecat@gmail.com>
This commit is contained in:
@@ -238,6 +238,28 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
|
|||||||
expect(isPassValid).to.equal(true);
|
expect(isPassValid).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('changes the apiToken on password reset', async () => {
|
||||||
|
const user = await generateUser();
|
||||||
|
const previousToken = user.apiToken;
|
||||||
|
|
||||||
|
const code = encrypt(JSON.stringify({
|
||||||
|
userId: user._id,
|
||||||
|
expiresAt: moment().add({ days: 1 }),
|
||||||
|
}));
|
||||||
|
await user.updateOne({
|
||||||
|
'auth.local.passwordResetCode': code,
|
||||||
|
});
|
||||||
|
|
||||||
|
await api.post(`${endpoint}`, {
|
||||||
|
newPassword: 'my new password',
|
||||||
|
confirmPassword: 'my new password',
|
||||||
|
code,
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.sync();
|
||||||
|
expect(user.apiToken).to.not.eql(previousToken);
|
||||||
|
});
|
||||||
|
|
||||||
it('renders the success page and convert the password from sha1 to bcrypt', async () => {
|
it('renders the success page and convert the password from sha1 to bcrypt', async () => {
|
||||||
const user = await generateUser();
|
const user = await generateUser();
|
||||||
|
|
||||||
|
|||||||
@@ -27,11 +27,30 @@ describe('PUT /user/auth/update-password', async () => {
|
|||||||
newPassword,
|
newPassword,
|
||||||
confirmPassword: newPassword,
|
confirmPassword: newPassword,
|
||||||
});
|
});
|
||||||
expect(response).to.eql({});
|
|
||||||
|
expect(response).to.exist;
|
||||||
|
expect(response.apiToken).to.exist;
|
||||||
|
|
||||||
await user.sync();
|
await user.sync();
|
||||||
expect(user.auth.local.hashed_password).to.not.eql(previousHashedPassword);
|
expect(user.auth.local.hashed_password).to.not.eql(previousHashedPassword);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should change the apiToken on password change', async () => {
|
||||||
|
const previousToken = user.apiToken;
|
||||||
|
const response = await user.put(ENDPOINT, {
|
||||||
|
password,
|
||||||
|
newPassword,
|
||||||
|
confirmPassword: newPassword,
|
||||||
|
});
|
||||||
|
|
||||||
|
const newToken = response.apiToken;
|
||||||
|
expect(newToken).to.exist;
|
||||||
|
|
||||||
|
await user.sync();
|
||||||
|
expect(user.apiToken).to.eql(newToken);
|
||||||
|
expect(user.apiToken).to.not.eql(previousToken);
|
||||||
|
});
|
||||||
|
|
||||||
it('returns an error when confirmPassword does not match newPassword', async () => {
|
it('returns an error when confirmPassword does not match newPassword', async () => {
|
||||||
await expect(user.put(ENDPOINT, {
|
await expect(user.put(ENDPOINT, {
|
||||||
password,
|
password,
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ import axios from 'axios';
|
|||||||
import * as Analytics from '@/libs/analytics';
|
import * as Analytics from '@/libs/analytics';
|
||||||
import { mapState } from '@/libs/store';
|
import { mapState } from '@/libs/store';
|
||||||
import snackbars from '@/components/snackbars/notifications';
|
import snackbars from '@/components/snackbars/notifications';
|
||||||
|
import { LOCALSTORAGE_AUTH_KEY } from '@/libs/auth';
|
||||||
|
|
||||||
const COMMUNITY_MANAGER_EMAIL = import.meta.env.EMAILS_COMMUNITY_MANAGER_EMAIL;
|
const COMMUNITY_MANAGER_EMAIL = import.meta.env.EMAILS_COMMUNITY_MANAGER_EMAIL;
|
||||||
|
|
||||||
@@ -280,7 +281,7 @@ export default {
|
|||||||
this.loading = false;
|
this.loading = false;
|
||||||
},
|
},
|
||||||
checkForBannedUser (error) {
|
checkForBannedUser (error) {
|
||||||
const AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
const AUTH_SETTINGS = localStorage.getItem(LOCALSTORAGE_AUTH_KEY);
|
||||||
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
||||||
const errorMessage = error.response.data.message;
|
const errorMessage = error.response.data.message;
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import markdownDirective from '@/directives/markdown';
|
import markdownDirective from '@/directives/markdown';
|
||||||
|
import { LOCALSTORAGE_AUTH_KEY } from '@/libs/auth';
|
||||||
|
|
||||||
const COMMUNITY_MANAGER_EMAIL = import.meta.env.EMAILS_COMMUNITY_MANAGER_EMAIL; // eslint-disable-line
|
const COMMUNITY_MANAGER_EMAIL = import.meta.env.EMAILS_COMMUNITY_MANAGER_EMAIL; // eslint-disable-line
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
bannedMessage () {
|
bannedMessage () {
|
||||||
const AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
const AUTH_SETTINGS = localStorage.getItem(LOCALSTORAGE_AUTH_KEY);
|
||||||
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
||||||
const userId = parseSettings ? parseSettings.auth.apiId : '';
|
const userId = parseSettings ? parseSettings.auth.apiId : '';
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
|
export const LOCALSTORAGE_AUTH_KEY = 'habit-mobile-settings';
|
||||||
|
|
||||||
|
export function authAsCredentialsState (authObject) {
|
||||||
|
return {
|
||||||
|
API_ID: authObject.auth.apiId,
|
||||||
|
API_TOKEN: authObject.auth.apiToken,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function setUpAxios (AUTH_SETTINGS) { // eslint-disable-line import/prefer-default-export
|
export function setUpAxios (AUTH_SETTINGS) { // eslint-disable-line import/prefer-default-export
|
||||||
if (!AUTH_SETTINGS) {
|
if (!AUTH_SETTINGS) {
|
||||||
AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings'); // eslint-disable-line no-param-reassign, max-len
|
AUTH_SETTINGS = localStorage.getItem(LOCALSTORAGE_AUTH_KEY); // eslint-disable-line no-param-reassign, max-len
|
||||||
if (!AUTH_SETTINGS) return false;
|
if (!AUTH_SETTINGS) return false;
|
||||||
AUTH_SETTINGS = JSON.parse(AUTH_SETTINGS); // eslint-disable-line no-param-reassign
|
AUTH_SETTINGS = JSON.parse(AUTH_SETTINGS); // eslint-disable-line no-param-reassign
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { LOCALSTORAGE_AUTH_KEY } from '@/libs/auth';
|
||||||
|
|
||||||
// @TODO: I have abstracted this in another PR. Use that function when merged
|
// @TODO: I have abstracted this in another PR. Use that function when merged
|
||||||
function getApiKey () {
|
function getApiKey () {
|
||||||
let AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
let AUTH_SETTINGS = localStorage.getItem(LOCALSTORAGE_AUTH_KEY);
|
||||||
|
|
||||||
if (AUTH_SETTINGS) {
|
if (AUTH_SETTINGS) {
|
||||||
AUTH_SETTINGS = JSON.parse(AUTH_SETTINGS);
|
AUTH_SETTINGS = JSON.parse(AUTH_SETTINGS);
|
||||||
|
|||||||
@@ -158,7 +158,14 @@ export default {
|
|||||||
confirmPassword: this.passwordUpdates.confirmPassword,
|
confirmPassword: this.passwordUpdates.confirmPassword,
|
||||||
};
|
};
|
||||||
|
|
||||||
await axios.put('/api/v4/user/auth/update-password', localAuthData);
|
const updatePasswordResult = await axios.put('/api/v4/user/auth/update-password', localAuthData);
|
||||||
|
|
||||||
|
const newToken = updatePasswordResult.data.data.apiToken;
|
||||||
|
|
||||||
|
this.$store.dispatch('auth:setNewToken', {
|
||||||
|
userId: this.user._id,
|
||||||
|
apiToken: newToken,
|
||||||
|
});
|
||||||
|
|
||||||
this.passwordUpdates = {};
|
this.passwordUpdates = {};
|
||||||
this.$store.dispatch('snackbars:add', {
|
this.$store.dispatch('snackbars:add', {
|
||||||
|
|||||||
@@ -147,8 +147,6 @@ import {
|
|||||||
const bugReportModal = () => import('@/components/bugReportModal');
|
const bugReportModal = () => import('@/components/bugReportModal');
|
||||||
const bugReportSuccessModal = () => import('@/components/bugReportSuccessModal');
|
const bugReportSuccessModal = () => import('@/components/bugReportSuccessModal');
|
||||||
|
|
||||||
const COMMUNITY_MANAGER_EMAIL = import.meta.env.EMAILS_COMMUNITY_MANAGER_EMAIL;
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
@@ -325,29 +323,6 @@ export default {
|
|||||||
if (loadingScreen) document.body.removeChild(loadingScreen);
|
if (loadingScreen) document.body.removeChild(loadingScreen);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
checkForBannedUser (error) {
|
|
||||||
const AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
|
||||||
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
|
||||||
const errorMessage = error.response.data.message;
|
|
||||||
|
|
||||||
// Case where user is not logged in
|
|
||||||
if (!parseSettings) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bannedMessage = this.$t('accountSuspended', {
|
|
||||||
communityManagerEmail: COMMUNITY_MANAGER_EMAIL,
|
|
||||||
userId: parseSettings.auth.apiId,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (errorMessage !== bannedMessage) return false;
|
|
||||||
|
|
||||||
this.$store.dispatch('auth:logout', { redirectToLogin: true });
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
itemSelected (item) {
|
|
||||||
this.selectedItemToBuy = item;
|
|
||||||
},
|
|
||||||
genericPurchase (item) {
|
genericPurchase (item) {
|
||||||
if (!item) return false;
|
if (!item) return false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,20 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { authAsCredentialsState, LOCALSTORAGE_AUTH_KEY } from '@/libs/auth';
|
||||||
|
|
||||||
const LOCALSTORAGE_AUTH_KEY = 'habit-mobile-settings';
|
function saveLocalDataAuth (store, apiId, apiToken) {
|
||||||
|
const credentialsObj = {
|
||||||
|
auth: {
|
||||||
|
apiId,
|
||||||
|
apiToken,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const userLocalData = JSON.stringify(credentialsObj);
|
||||||
|
|
||||||
|
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
||||||
|
|
||||||
|
store.state.credentials = authAsCredentialsState(credentialsObj);
|
||||||
|
}
|
||||||
|
|
||||||
export async function register (store, params) {
|
export async function register (store, params) {
|
||||||
let url = '/api/v4/user/auth/local/register';
|
let url = '/api/v4/user/auth/local/register';
|
||||||
@@ -16,13 +30,7 @@ export async function register (store, params) {
|
|||||||
|
|
||||||
const user = result.data.data;
|
const user = result.data.data;
|
||||||
|
|
||||||
const userLocalData = JSON.stringify({
|
saveLocalDataAuth(store, user.id, user.apiToken);
|
||||||
auth: {
|
|
||||||
apiId: user._id,
|
|
||||||
apiToken: user.apiToken,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function login (store, params) {
|
export async function login (store, params) {
|
||||||
@@ -35,14 +43,7 @@ export async function login (store, params) {
|
|||||||
|
|
||||||
const user = result.data.data;
|
const user = result.data.data;
|
||||||
|
|
||||||
const userLocalData = JSON.stringify({
|
saveLocalDataAuth(store, user.id, user.apiToken);
|
||||||
auth: {
|
|
||||||
apiId: user.id,
|
|
||||||
apiToken: user.apiToken,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function verifyUsername (store, params) {
|
export async function verifyUsername (store, params) {
|
||||||
@@ -72,14 +73,7 @@ export async function socialAuth (store, params) {
|
|||||||
|
|
||||||
const user = result.data.data;
|
const user = result.data.data;
|
||||||
|
|
||||||
const userLocalData = JSON.stringify({
|
saveLocalDataAuth(store, user.id, user.apiToken);
|
||||||
auth: {
|
|
||||||
apiId: user.id,
|
|
||||||
apiToken: user.apiToken,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function appleAuth (store, params) {
|
export async function appleAuth (store, params) {
|
||||||
@@ -93,14 +87,7 @@ export async function appleAuth (store, params) {
|
|||||||
|
|
||||||
const user = result.data.data;
|
const user = result.data.data;
|
||||||
|
|
||||||
const userLocalData = JSON.stringify({
|
saveLocalDataAuth(store, user.id, user.apiToken);
|
||||||
auth: {
|
|
||||||
apiId: user.id,
|
|
||||||
apiToken: user.apiToken,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logout (store, options = {}) {
|
export function logout (store, options = {}) {
|
||||||
@@ -108,3 +95,7 @@ export function logout (store, options = {}) {
|
|||||||
const query = options.redirectToLogin === true ? '?redirectToLogin=true' : '';
|
const query = options.redirectToLogin === true ? '?redirectToLogin=true' : '';
|
||||||
window.location.href = `/logout-server${query}`;
|
window.location.href = `/logout-server${query}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setNewToken (store, params) {
|
||||||
|
saveLocalDataAuth(store, params.userId, params.apiToken);
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { DAY_MAPPING } from '@/../../common/script/cron';
|
|||||||
import deepFreeze from '@/libs/deepFreeze';
|
import deepFreeze from '@/libs/deepFreeze';
|
||||||
import Store from '@/libs/store';
|
import Store from '@/libs/store';
|
||||||
import { asyncResourceFactory } from '@/libs/asyncResource';
|
import { asyncResourceFactory } from '@/libs/asyncResource';
|
||||||
import { setUpAxios } from '@/libs/auth';
|
import { authAsCredentialsState, LOCALSTORAGE_AUTH_KEY, setUpAxios } from '@/libs/auth';
|
||||||
|
|
||||||
import actions from './actions';
|
import actions from './actions';
|
||||||
import getters from './getters';
|
import getters from './getters';
|
||||||
@@ -22,7 +22,7 @@ const browserTimezoneUtcOffset = moment().utcOffset();
|
|||||||
|
|
||||||
axios.defaults.headers.common['x-client'] = 'habitica-web';
|
axios.defaults.headers.common['x-client'] = 'habitica-web';
|
||||||
|
|
||||||
let AUTH_SETTINGS = window.localStorage.getItem('habit-mobile-settings');
|
let AUTH_SETTINGS = window.localStorage.getItem(LOCALSTORAGE_AUTH_KEY);
|
||||||
if (AUTH_SETTINGS) {
|
if (AUTH_SETTINGS) {
|
||||||
AUTH_SETTINGS = JSON.parse(AUTH_SETTINGS);
|
AUTH_SETTINGS = JSON.parse(AUTH_SETTINGS);
|
||||||
isUserLoggedIn = setUpAxios(AUTH_SETTINGS);
|
isUserLoggedIn = setUpAxios(AUTH_SETTINGS);
|
||||||
@@ -64,10 +64,7 @@ export default function clientStore () {
|
|||||||
// see https://github.com/HabitRPG/habitica/issues/9242
|
// see https://github.com/HabitRPG/habitica/issues/9242
|
||||||
notificationsRemoved: [],
|
notificationsRemoved: [],
|
||||||
worldState: asyncResourceFactory(),
|
worldState: asyncResourceFactory(),
|
||||||
credentials: isUserLoggedIn ? {
|
credentials: isUserLoggedIn ? authAsCredentialsState(AUTH_SETTINGS) : {},
|
||||||
API_ID: AUTH_SETTINGS.auth.apiId,
|
|
||||||
API_TOKEN: AUTH_SETTINGS.auth.apiToken,
|
|
||||||
} : {},
|
|
||||||
// store the timezone offset in case it's different than the one in
|
// store the timezone offset in case it's different than the one in
|
||||||
// user.preferences.timezoneOffset and change it after the user is synced
|
// user.preferences.timezoneOffset and change it after the user is synced
|
||||||
// in app.vue
|
// in app.vue
|
||||||
|
|||||||
@@ -87,13 +87,12 @@
|
|||||||
"API": "API",
|
"API": "API",
|
||||||
"APICopied": "API token copied to clipboard.",
|
"APICopied": "API token copied to clipboard.",
|
||||||
"APITokenTitle": "API Token",
|
"APITokenTitle": "API Token",
|
||||||
"APITokenDisclaimer": "<b>Your API Token is like a password; Do not share it publicly.</b> You may occasionally be asked for your User ID, but never post your API Token where others can see it, including on Github.<br><br><b>Note:</b> If you need a new API Token (e.g., if you accidentally shared it), email <a href='mailto:admin@habitica.com' target='_blank'>admin@habitica.com</a> with your User ID and current Token. Once it is reset you will need to re-authorize everything by logging out of the website and mobile app and by providing the new Token to any other Habitica tools that you use.",
|
"APITokenDisclaimer": "<b>Your API Token is like a password; Do not share it publicly.</b> You may occasionally be asked for your User ID, but never post your API Token where others can see it, including on Github.<br><br><b>If you need a new API Token</b> (e.g., if you accidentally shared it), you can change your password to reset it. Once it is reset, you will need to log back in to any other devices you use Habitica on and provide the new API Token to third-party tools you may use.",
|
||||||
"APIv3": "API v3",
|
"APIv3": "API v3",
|
||||||
"APIText": "Copy these for use in third party applications. However, think of your API Token like a password, and do not share it publicly. You may occasionally be asked for your User ID, but never post your API Token where others can see it, including on Github.",
|
"APIText": "Copy these for use in third party applications. However, think of your API Token like a password, and do not share it publicly. You may occasionally be asked for your User ID, but never post your API Token where others can see it, including on Github.",
|
||||||
"APIToken": "API Token (this is a password - see warning above!)",
|
"APIToken": "API Token (this is a password - see warning above!)",
|
||||||
"showAPIToken": "Show API Token",
|
"showAPIToken": "Show API Token",
|
||||||
"hideAPIToken": "Hide API Token",
|
"hideAPIToken": "Hide API Token",
|
||||||
"APITokenWarning": "If you need a new API Token (e.g., if you accidentally shared it), email <%= hrefTechAssistanceEmail %> with your User ID and current Token. Once it is reset you will need to re-authorize everything by logging out of the website and mobile app and by providing the new Token to any other Habitica tools that you use.",
|
|
||||||
"thirdPartyApps": "Third Party Apps",
|
"thirdPartyApps": "Third Party Apps",
|
||||||
"thirdPartyTools": "Find third party apps, extensions, and all kinds of other tools you can use with your account on the <a href='https://habitica.fandom.com/wiki/Extensions,_Add-Ons,_and_Customizations' target='_blank'>Habitica wiki</a>.",
|
"thirdPartyTools": "Find third party apps, extensions, and all kinds of other tools you can use with your account on the <a href='https://habitica.fandom.com/wiki/Extensions,_Add-Ons,_and_Customizations' target='_blank'>Habitica wiki</a>.",
|
||||||
"resetDo": "Do it, reset my account!",
|
"resetDo": "Do it, reset my account!",
|
||||||
@@ -212,7 +211,7 @@
|
|||||||
"changeUsernameDisclaimer": "Your username is used for invitations, @mentions in chat, and messaging. It must be 1 to 20 characters, containing only letters a to z, numbers 0 to 9, hyphens, or underscores, and cannot include any inappropriate terms.",
|
"changeUsernameDisclaimer": "Your username is used for invitations, @mentions in chat, and messaging. It must be 1 to 20 characters, containing only letters a to z, numbers 0 to 9, hyphens, or underscores, and cannot include any inappropriate terms.",
|
||||||
"changeEmailDisclaimer": "This is the email address that you use to log in to Habitica, as well as receive notifications.",
|
"changeEmailDisclaimer": "This is the email address that you use to log in to Habitica, as well as receive notifications.",
|
||||||
"changeDisplayNameDisclaimer": "This is the name that will be displayed for your Avatar in Habitica.",
|
"changeDisplayNameDisclaimer": "This is the name that will be displayed for your Avatar in Habitica.",
|
||||||
"changePasswordDisclaimer": "Password must be 8 characters or more. We recommend a strong password that you're not using elsewhere.",
|
"changePasswordDisclaimer": "Passwords must be 8 characters or more. Changing your password will log you out of any other devices and third-party tools you may use.",
|
||||||
"dateFormatDisclaimer": "Adjust the date formatting across Habitica.",
|
"dateFormatDisclaimer": "Adjust the date formatting across Habitica.",
|
||||||
"verifyUsernameVeteranPet": "One of these Veteran Pets will be waiting for you after you've finished confirming!",
|
"verifyUsernameVeteranPet": "One of these Veteran Pets will be waiting for you after you've finished confirming!",
|
||||||
"enableAudio": "Enable Audio",
|
"enableAudio": "Enable Audio",
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ api.updateUsername = {
|
|||||||
* @apiParam (Body) {String} newPassword The new password
|
* @apiParam (Body) {String} newPassword The new password
|
||||||
* @apiParam (Body) {String} confirmPassword New password confirmation
|
* @apiParam (Body) {String} confirmPassword New password confirmation
|
||||||
*
|
*
|
||||||
* @apiSuccess {Object} data An empty object
|
* @apiSuccess {String} data.apiToken The new apiToken
|
||||||
* */
|
* */
|
||||||
api.updatePassword = {
|
api.updatePassword = {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
@@ -316,9 +316,14 @@ api.updatePassword = {
|
|||||||
|
|
||||||
// set new password and make sure it's using bcrypt for hashing
|
// set new password and make sure it's using bcrypt for hashing
|
||||||
await passwordUtils.convertToBcrypt(user, newPassword);
|
await passwordUtils.convertToBcrypt(user, newPassword);
|
||||||
|
|
||||||
|
user.apiToken = common.uuid();
|
||||||
|
|
||||||
await user.save();
|
await user.save();
|
||||||
|
|
||||||
res.respond(200, {});
|
res.respond(200, {
|
||||||
|
apiToken: user.apiToken,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -350,6 +355,7 @@ api.resetPassword = {
|
|||||||
{ 'auth.local.email': email }, // Prefer to reset password for local auth
|
{ 'auth.local.email': email }, // Prefer to reset password for local auth
|
||||||
{ auth: 1 },
|
{ auth: 1 },
|
||||||
).exec();
|
).exec();
|
||||||
|
|
||||||
if (!user) { // If no local auth with that email...
|
if (!user) { // If no local auth with that email...
|
||||||
const potentialUsers = await User.find(
|
const potentialUsers = await User.find(
|
||||||
{
|
{
|
||||||
@@ -486,6 +492,9 @@ api.resetPasswordSetNewOne = {
|
|||||||
await passwordUtils.convertToBcrypt(user, String(newPassword));
|
await passwordUtils.convertToBcrypt(user, String(newPassword));
|
||||||
user.auth.local.passwordResetCode = undefined; // Reset saved password reset code
|
user.auth.local.passwordResetCode = undefined; // Reset saved password reset code
|
||||||
if (!user.auth.local.email) user.auth.local.email = await socialEmailToLocal(user);
|
if (!user.auth.local.email) user.auth.local.email = await socialEmailToLocal(user);
|
||||||
|
|
||||||
|
user.apiToken = common.uuid();
|
||||||
|
|
||||||
await user.save();
|
await user.save();
|
||||||
|
|
||||||
return res.respond(200, {}, res.t('passwordChangeSuccess'));
|
return res.respond(200, {}, res.t('passwordChangeSuccess'));
|
||||||
|
|||||||
Reference in New Issue
Block a user