mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 22:27:48 +00:00
Begin preliminary tokenVersion impl
This commit is contained in:
@@ -4,14 +4,21 @@ import jwt from 'jsonwebtoken';
|
|||||||
import * as bigintConversion from 'bigint-conversion';
|
import * as bigintConversion from 'bigint-conversion';
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const jsrp = require('jsrp');
|
const jsrp = require('jsrp');
|
||||||
import { User, LoginSRPDetail } from '../../models';
|
import {
|
||||||
|
User,
|
||||||
|
LoginSRPDetail,
|
||||||
|
TokenVersion
|
||||||
|
} from '../../models';
|
||||||
import { createToken, issueAuthTokens, clearTokens } from '../../helpers/auth';
|
import { createToken, issueAuthTokens, clearTokens } from '../../helpers/auth';
|
||||||
import { checkUserDevice } from '../../helpers/user';
|
import { checkUserDevice } from '../../helpers/user';
|
||||||
import {
|
import {
|
||||||
ACTION_LOGIN,
|
ACTION_LOGIN,
|
||||||
ACTION_LOGOUT
|
ACTION_LOGOUT
|
||||||
} from '../../variables';
|
} from '../../variables';
|
||||||
import { BadRequestError } from '../../utils/errors';
|
import {
|
||||||
|
BadRequestError,
|
||||||
|
UnauthorizedRequestError
|
||||||
|
} from '../../utils/errors';
|
||||||
import { EELogService } from '../../ee/services';
|
import { EELogService } from '../../ee/services';
|
||||||
import { getChannelFromUserAgent } from '../../utils/posthog';
|
import { getChannelFromUserAgent } from '../../utils/posthog';
|
||||||
import {
|
import {
|
||||||
@@ -241,19 +248,31 @@ export const getNewToken = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
_id: decodedToken.userId
|
_id: decodedToken.userId
|
||||||
}).select('+publicKey +refreshVersion');
|
}).select('+publicKey +refreshVersion +accessVersion');
|
||||||
|
|
||||||
if (!user) throw new Error('Failed to authenticate unfound user');
|
if (!user) throw new Error('Failed to authenticate unfound user');
|
||||||
if (!user?.publicKey)
|
if (!user?.publicKey)
|
||||||
throw new Error('Failed to authenticate not fully set up account');
|
throw new Error('Failed to authenticate not fully set up account');
|
||||||
|
|
||||||
if (decodedToken?.refreshVersion !== user.refreshVersion) throw BadRequestError({
|
const tokenVersion = await TokenVersion.findOne({
|
||||||
|
_id: decodedToken.tokenVersionId,
|
||||||
|
user: user._id
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('tokenVersion: ', tokenVersion);
|
||||||
|
|
||||||
|
if (!tokenVersion) throw UnauthorizedRequestError({
|
||||||
|
message: 'Failed to validate refresh token'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (decodedToken.refreshVersion !== tokenVersion.refreshVersion) throw BadRequestError({
|
||||||
message: 'Failed to validate refresh token'
|
message: 'Failed to validate refresh token'
|
||||||
});
|
});
|
||||||
|
|
||||||
const token = createToken({
|
const token = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
userId: decodedToken.userId
|
userId: decodedToken.userId,
|
||||||
|
accessVersion: tokenVersion.refreshVersion
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtAuthLifetime(),
|
expiresIn: await getJwtAuthLifetime(),
|
||||||
secret: await getJwtAuthSecret()
|
secret: await getJwtAuthSecret()
|
||||||
|
|||||||
@@ -231,16 +231,16 @@ export const changePassword = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// await clearTokens(user._id);
|
await clearTokens(user._id);
|
||||||
|
|
||||||
// // clear httpOnly cookie
|
// clear httpOnly cookie
|
||||||
|
|
||||||
// res.cookie('jid', '', {
|
res.cookie('jid', '', {
|
||||||
// httpOnly: true,
|
httpOnly: true,
|
||||||
// path: '/',
|
path: '/',
|
||||||
// sameSite: 'strict',
|
sameSite: 'strict',
|
||||||
// secure: (await getHttpsEnabled()) as boolean
|
secure: (await getHttpsEnabled()) as boolean
|
||||||
// });
|
});
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
message: 'Successfully changed password'
|
message: 'Successfully changed password'
|
||||||
|
|||||||
@@ -235,8 +235,6 @@ export const login2 = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
import { validateUserEmail } from '../../validation';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send MFA token to email [email]
|
* Send MFA token to email [email]
|
||||||
* @param req
|
* @param req
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ export const login2 = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
email,
|
email,
|
||||||
}).select('+salt +verifier +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag +publicKey +encryptedPrivateKey +iv +tag');
|
}).select('+salt +verifier +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag +publicKey +encryptedPrivateKey +iv +tag +devices');
|
||||||
|
|
||||||
if (!user) throw new Error('Failed to find user');
|
if (!user) throw new Error('Failed to find user');
|
||||||
|
|
||||||
@@ -183,6 +183,10 @@ export const login2 = async (req: Request, res: Response) => {
|
|||||||
userAgent: req.headers['user-agent'] ?? ''
|
userAgent: req.headers['user-agent'] ?? ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('logged in, issue tokens');
|
||||||
|
console.log('ip: ', req.ip);
|
||||||
|
console.log('userAgent: ', req.headers['user-agent']);
|
||||||
|
|
||||||
// issue tokens
|
// issue tokens
|
||||||
const tokens = await issueAuthTokens({ userId: user._id.toString() });
|
const tokens = await issueAuthTokens({ userId: user._id.toString() });
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import {
|
|||||||
User,
|
User,
|
||||||
ServiceTokenData,
|
ServiceTokenData,
|
||||||
ServiceAccount,
|
ServiceAccount,
|
||||||
APIKeyData
|
APIKeyData,
|
||||||
|
TokenVersion
|
||||||
} from '../models';
|
} from '../models';
|
||||||
import {
|
import {
|
||||||
AccountNotFoundError,
|
AccountNotFoundError,
|
||||||
@@ -108,11 +109,32 @@ export const getAuthUserPayload = async ({
|
|||||||
|
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
_id: decodedToken.userId
|
_id: decodedToken.userId
|
||||||
}).select('+publicKey');
|
}).select('+publicKey +accessVersion');
|
||||||
|
|
||||||
if (!user) throw AccountNotFoundError({ message: 'Failed to find User' });
|
if (!user) throw AccountNotFoundError({ message: 'Failed to find user' });
|
||||||
|
|
||||||
if (!user?.publicKey) throw UnauthorizedRequestError({ message: 'Failed to authenticate User with partially set up account' });
|
if (!user?.publicKey) throw UnauthorizedRequestError({ message: 'Failed to authenticate user with partially set up account' });
|
||||||
|
|
||||||
|
console.log('getAuthUserPayload');
|
||||||
|
|
||||||
|
const tokenVersion = await TokenVersion.findOne({
|
||||||
|
_id: decodedToken.tokenVersionId,
|
||||||
|
user: user._id
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('tokenVersion: ', tokenVersion);
|
||||||
|
|
||||||
|
if (!tokenVersion) throw UnauthorizedRequestError({
|
||||||
|
message: 'Failed to validate access token'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (decodedToken.accessVersion !== tokenVersion.accessVersion) {
|
||||||
|
console.log('incorrect version');
|
||||||
|
|
||||||
|
throw UnauthorizedRequestError({
|
||||||
|
message: 'Failed to validate access token'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
@@ -257,13 +279,22 @@ export const getAuthAPIKeyPayload = async ({
|
|||||||
*/
|
*/
|
||||||
export const issueAuthTokens = async ({ userId }: { userId: string }) => {
|
export const issueAuthTokens = async ({ userId }: { userId: string }) => {
|
||||||
|
|
||||||
const user = await User.findById(userId).select('+refreshVersion');
|
// TODO: create tokenVersion here
|
||||||
if (!user) throw AccountNotFoundError();
|
// TODO: include some kind of (channel) name here
|
||||||
|
|
||||||
|
const tokenVersion = await new TokenVersion({
|
||||||
|
user: new Types.ObjectId(userId),
|
||||||
|
name: '', // improve to channel
|
||||||
|
refreshVersion: 0,
|
||||||
|
accessVersion: 0
|
||||||
|
});
|
||||||
|
|
||||||
// issue tokens
|
// issue tokens
|
||||||
const token = createToken({
|
const token = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
userId
|
userId,
|
||||||
|
tokenVersionId: tokenVersion._id.toString(),
|
||||||
|
accessVersion: tokenVersion.accessVersion
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtAuthLifetime(),
|
expiresIn: await getJwtAuthLifetime(),
|
||||||
secret: await getJwtAuthSecret()
|
secret: await getJwtAuthSecret()
|
||||||
@@ -272,7 +303,8 @@ export const issueAuthTokens = async ({ userId }: { userId: string }) => {
|
|||||||
const refreshToken = createToken({
|
const refreshToken = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
userId,
|
userId,
|
||||||
refreshVersion: user.refreshVersion
|
tokenVersionId: tokenVersion._id.toString(),
|
||||||
|
refreshVersion: tokenVersion.refreshVersion
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtRefreshLifetime(),
|
expiresIn: await getJwtRefreshLifetime(),
|
||||||
secret: await getJwtRefreshSecret()
|
secret: await getJwtRefreshSecret()
|
||||||
@@ -291,11 +323,14 @@ export const issueAuthTokens = async ({ userId }: { userId: string }) => {
|
|||||||
*/
|
*/
|
||||||
export const clearTokens = async (userId: Types.ObjectId): Promise<void> => {
|
export const clearTokens = async (userId: Types.ObjectId): Promise<void> => {
|
||||||
// increment refreshVersion on user by 1
|
// increment refreshVersion on user by 1
|
||||||
|
|
||||||
|
// change this
|
||||||
await User.findOneAndUpdate({
|
await User.findOneAndUpdate({
|
||||||
_id: userId
|
_id: userId
|
||||||
}, {
|
}, {
|
||||||
$inc: {
|
$inc: {
|
||||||
refreshVersion: 1
|
refreshVersion: 1,
|
||||||
|
accessVersion: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
+68
-57
@@ -1,6 +1,6 @@
|
|||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
import express, { Request, NextFunction, Response } from "express";
|
import express from "express";
|
||||||
import helmet from "helmet";
|
import helmet from "helmet";
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
import { DatabaseService } from "./services";
|
import { DatabaseService } from "./services";
|
||||||
@@ -9,9 +9,10 @@ import { setUpHealthEndpoint } from "./services/health";
|
|||||||
import cookieParser from "cookie-parser";
|
import cookieParser from "cookie-parser";
|
||||||
import swaggerUi = require("swagger-ui-express");
|
import swaggerUi = require("swagger-ui-express");
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const swaggerFile = require('../spec.json');
|
const swaggerFile = require("../spec.json");
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
import { apiLimiter } from './helpers/rateLimiter';
|
const requestIp = require("request-ip");
|
||||||
|
import { apiLimiter } from "./helpers/rateLimiter";
|
||||||
import {
|
import {
|
||||||
workspace as eeWorkspaceRouter,
|
workspace as eeWorkspaceRouter,
|
||||||
secret as eeSecretRouter,
|
secret as eeSecretRouter,
|
||||||
@@ -73,81 +74,91 @@ const main = async () => {
|
|||||||
await EELicenseService.initGlobalFeatureSet();
|
await EELicenseService.initGlobalFeatureSet();
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.enable('trust proxy');
|
app.enable("trust proxy");
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(
|
app.use(
|
||||||
cors({
|
cors({
|
||||||
credentials: true,
|
credentials: true,
|
||||||
origin: await getSiteURL()
|
origin: await getSiteURL(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
if ((await getNodeEnv()) === 'production') {
|
app.use(requestIp.mw());
|
||||||
// enable app-wide rate-limiting + helmet security
|
|
||||||
// in production
|
if ((await getNodeEnv()) === "production") {
|
||||||
app.disable('x-powered-by');
|
// enable app-wide rate-limiting + helmet security
|
||||||
app.use(apiLimiter);
|
// in production
|
||||||
app.use(helmet());
|
app.disable("x-powered-by");
|
||||||
|
app.use(apiLimiter);
|
||||||
|
app.use(helmet());
|
||||||
}
|
}
|
||||||
|
|
||||||
// (EE) routes
|
// (EE) routes
|
||||||
app.use('/api/v1/secret', eeSecretRouter);
|
app.use("/api/v1/secret", eeSecretRouter);
|
||||||
app.use('/api/v1/secret-snapshot', eeSecretSnapshotRouter);
|
app.use("/api/v1/secret-snapshot", eeSecretSnapshotRouter);
|
||||||
app.use('/api/v1/workspace', eeWorkspaceRouter);
|
app.use("/api/v1/workspace", eeWorkspaceRouter);
|
||||||
app.use('/api/v1/action', eeActionRouter);
|
app.use("/api/v1/action", eeActionRouter);
|
||||||
app.use('/api/v1/organizations', eeOrganizationsRouter);
|
app.use("/api/v1/organizations", eeOrganizationsRouter);
|
||||||
app.use('/api/v1/cloud-products', eeCloudProductsRouter);
|
app.use("/api/v1/cloud-products", eeCloudProductsRouter);
|
||||||
|
|
||||||
// v1 routes (default)
|
// v1 routes (default)
|
||||||
app.use('/api/v1/signup', v1SignupRouter);
|
app.use("/api/v1/signup", v1SignupRouter);
|
||||||
app.use('/api/v1/auth', v1AuthRouter);
|
app.use("/api/v1/auth", v1AuthRouter);
|
||||||
app.use('/api/v1/bot', v1BotRouter);
|
app.use("/api/v1/bot", v1BotRouter);
|
||||||
app.use('/api/v1/user', v1UserRouter);
|
app.use("/api/v1/user", v1UserRouter);
|
||||||
app.use('/api/v1/user-action', v1UserActionRouter);
|
app.use("/api/v1/user-action", v1UserActionRouter);
|
||||||
app.use('/api/v1/organization', v1OrganizationRouter);
|
app.use("/api/v1/organization", v1OrganizationRouter);
|
||||||
app.use('/api/v1/workspace', v1WorkspaceRouter);
|
app.use("/api/v1/workspace", v1WorkspaceRouter);
|
||||||
app.use('/api/v1/membership-org', v1MembershipOrgRouter);
|
app.use("/api/v1/membership-org", v1MembershipOrgRouter);
|
||||||
app.use('/api/v1/membership', v1MembershipRouter);
|
app.use("/api/v1/membership", v1MembershipRouter);
|
||||||
app.use('/api/v1/key', v1KeyRouter);
|
app.use("/api/v1/key", v1KeyRouter);
|
||||||
app.use('/api/v1/invite-org', v1InviteOrgRouter);
|
app.use("/api/v1/invite-org", v1InviteOrgRouter);
|
||||||
app.use('/api/v1/secret', v1SecretRouter); // deprecate
|
app.use("/api/v1/secret", v1SecretRouter); // deprecate
|
||||||
app.use('/api/v1/service-token', v1ServiceTokenRouter); // deprecate
|
app.use("/api/v1/service-token", v1ServiceTokenRouter); // deprecate
|
||||||
app.use('/api/v1/password', v1PasswordRouter);
|
app.use("/api/v1/password", v1PasswordRouter);
|
||||||
app.use('/api/v1/stripe', v1StripeRouter);
|
app.use("/api/v1/stripe", v1StripeRouter);
|
||||||
app.use('/api/v1/integration', v1IntegrationRouter);
|
app.use("/api/v1/integration", v1IntegrationRouter);
|
||||||
app.use('/api/v1/integration-auth', v1IntegrationAuthRouter);
|
app.use("/api/v1/integration-auth", v1IntegrationAuthRouter);
|
||||||
app.use('/api/v1/folder', v1SecretsFolder)
|
app.use("/api/v1/folders", v1SecretsFolder);
|
||||||
|
|
||||||
// v2 routes (improvements)
|
// v2 routes (improvements)
|
||||||
app.use('/api/v2/signup', v2SignupRouter);
|
app.use("/api/v2/signup", v2SignupRouter);
|
||||||
app.use('/api/v2/auth', v2AuthRouter);
|
app.use("/api/v2/auth", v2AuthRouter);
|
||||||
app.use('/api/v2/users', v2UsersRouter);
|
app.use("/api/v2/users", v2UsersRouter);
|
||||||
app.use('/api/v2/organizations', v2OrganizationsRouter);
|
app.use("/api/v2/organizations", v2OrganizationsRouter);
|
||||||
app.use('/api/v2/workspace', v2EnvironmentRouter);
|
app.use("/api/v2/workspace", v2EnvironmentRouter);
|
||||||
app.use('/api/v2/workspace', v2TagsRouter);
|
app.use("/api/v2/workspace", v2TagsRouter);
|
||||||
app.use('/api/v2/workspace', v2WorkspaceRouter);
|
app.use("/api/v2/workspace", v2WorkspaceRouter);
|
||||||
app.use('/api/v2/secret', v2SecretRouter); // deprecate
|
app.use("/api/v2/secret", v2SecretRouter); // deprecate
|
||||||
app.use('/api/v2/secrets', v2SecretsRouter); // note: in the process of moving to v3/secrets
|
app.use("/api/v2/secrets", v2SecretsRouter); // note: in the process of moving to v3/secrets
|
||||||
app.use('/api/v2/service-token', v2ServiceTokenDataRouter);
|
app.use("/api/v2/service-token", v2ServiceTokenDataRouter);
|
||||||
app.use('/api/v2/service-accounts', v2ServiceAccountsRouter); // new
|
app.use("/api/v2/service-accounts", v2ServiceAccountsRouter); // new
|
||||||
app.use('/api/v2/api-key', v2APIKeyDataRouter);
|
app.use("/api/v2/api-key", v2APIKeyDataRouter);
|
||||||
|
|
||||||
// v3 routes (experimental)
|
// v3 routes (experimental)
|
||||||
app.use('/api/v3/secrets', v3SecretsRouter);
|
app.use("/api/v3/auth", v3AuthRouter);
|
||||||
app.use('/api/v3/workspaces', v3WorkspacesRouter);
|
app.use("/api/v3/secrets", v3SecretsRouter);
|
||||||
|
app.use("/api/v3/workspaces", v3WorkspacesRouter);
|
||||||
|
app.use("/api/v3/signup", v3SignupRouter);
|
||||||
|
|
||||||
// api docs
|
// api docs
|
||||||
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerFile))
|
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerFile));
|
||||||
|
|
||||||
// server status
|
// server status
|
||||||
app.use('/api', healthCheck)
|
app.use("/api", healthCheck);
|
||||||
|
|
||||||
//* Handle unrouted requests and respond with proper error message as well as status code
|
//* Handle unrouted requests and respond with proper error message as well as status code
|
||||||
app.use((req: Request, res: Response, next: NextFunction) => {
|
app.use((req, res, next) => {
|
||||||
if (res.headersSent) return next();
|
if (res.headersSent) return next();
|
||||||
next(RouteNotFoundError({ message: `The requested source '(${req.method})${req.url}' was not found` }))
|
next(
|
||||||
})
|
RouteNotFoundError({
|
||||||
|
message: `The requested source '(${req.method})${req.url}' was not found`,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(requestErrorHandler);
|
||||||
|
|
||||||
const server = app.listen(await getPort(), async () => {
|
const server = app.listen(await getPort(), async () => {
|
||||||
(await getLogger("backend-main")).info(
|
(await getLogger("backend-main")).info(
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import Workspace, { IWorkspace } from './workspace';
|
|||||||
import ServiceTokenData, { IServiceTokenData } from './serviceTokenData';
|
import ServiceTokenData, { IServiceTokenData } from './serviceTokenData';
|
||||||
import APIKeyData, { IAPIKeyData } from './apiKeyData';
|
import APIKeyData, { IAPIKeyData } from './apiKeyData';
|
||||||
import LoginSRPDetail, { ILoginSRPDetail } from './loginSRPDetail';
|
import LoginSRPDetail, { ILoginSRPDetail } from './loginSRPDetail';
|
||||||
|
import TokenVersion, { ITokenVersion } from './tokenVersion';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
AuthProvider,
|
AuthProvider,
|
||||||
@@ -72,5 +73,7 @@ export {
|
|||||||
APIKeyData,
|
APIKeyData,
|
||||||
IAPIKeyData,
|
IAPIKeyData,
|
||||||
LoginSRPDetail,
|
LoginSRPDetail,
|
||||||
ILoginSRPDetail
|
ILoginSRPDetail,
|
||||||
|
TokenVersion,
|
||||||
|
ITokenVersion
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { Schema, model, Types, Document } from 'mongoose';
|
||||||
|
|
||||||
|
export interface ITokenVersion extends Document {
|
||||||
|
user: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
refreshVersion: number;
|
||||||
|
accessVersion: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenVersionSchema = new Schema<ITokenVersion>(
|
||||||
|
{
|
||||||
|
user: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: 'User',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
refreshVersion: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
accessVersion: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const TokenVersion = model<ITokenVersion>('TokenVersion', tokenVersionSchema);
|
||||||
|
|
||||||
|
export default TokenVersion;
|
||||||
@@ -21,7 +21,6 @@ export interface IUser extends Document {
|
|||||||
tag?: string;
|
tag?: string;
|
||||||
salt?: string;
|
salt?: string;
|
||||||
verifier?: string;
|
verifier?: string;
|
||||||
refreshVersion: number;
|
|
||||||
isMfaEnabled: boolean;
|
isMfaEnabled: boolean;
|
||||||
mfaMethods: boolean;
|
mfaMethods: boolean;
|
||||||
devices: {
|
devices: {
|
||||||
@@ -91,11 +90,6 @@ const userSchema = new Schema<IUser>(
|
|||||||
type: String,
|
type: String,
|
||||||
select: false
|
select: false
|
||||||
},
|
},
|
||||||
refreshVersion: {
|
|
||||||
type: Number,
|
|
||||||
default: 0,
|
|
||||||
select: false
|
|
||||||
},
|
|
||||||
isMfaEnabled: {
|
isMfaEnabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
|||||||
@@ -125,6 +125,10 @@ const changePassword = async (
|
|||||||
setPasswordChanged(true);
|
setPasswordChanged(true);
|
||||||
setCurrentPassword('');
|
setCurrentPassword('');
|
||||||
setNewPassword('');
|
setNewPassword('');
|
||||||
|
|
||||||
|
window.location.href = '/login';
|
||||||
|
|
||||||
|
// move to login page
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setCurrentPasswordError(true);
|
setCurrentPasswordError(true);
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|||||||
Reference in New Issue
Block a user