mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-10 16:28:40 +00:00
296 lines
6.8 KiB
TypeScript
296 lines
6.8 KiB
TypeScript
import { Request, Response } from "express";
|
|
import { Types } from "mongoose";
|
|
import crypto from "crypto";
|
|
import bcrypt from "bcrypt";
|
|
import {
|
|
APIKeyData,
|
|
AuthProvider,
|
|
MembershipOrg,
|
|
TokenVersion,
|
|
User
|
|
} from "../../models";
|
|
import { getSaltRounds } from "../../config";
|
|
|
|
/**
|
|
* Return the current user.
|
|
* @param req
|
|
* @param res
|
|
* @returns
|
|
*/
|
|
export const getMe = async (req: Request, res: Response) => {
|
|
/*
|
|
#swagger.summary = "Retrieve the current user on the request"
|
|
#swagger.description = "Retrieve the current user on the request"
|
|
|
|
#swagger.security = [{
|
|
"apiKeyAuth": []
|
|
}]
|
|
|
|
#swagger.responses[200] = {
|
|
content: {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"user": {
|
|
"type": "object",
|
|
$ref: "#/components/schemas/CurrentUser",
|
|
"description": "Current user on request"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
const user = await User
|
|
.findById(req.user._id)
|
|
.select("+salt +publicKey +encryptedPrivateKey +iv +tag +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag");
|
|
|
|
return res.status(200).send({
|
|
user,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Update the current user's MFA-enabled status [isMfaEnabled].
|
|
* Note: Infisical currently only supports email-based 2FA only; this will expand to
|
|
* include SMS and authenticator app modes of authentication in the future.
|
|
* @param req
|
|
* @param res
|
|
* @returns
|
|
*/
|
|
export const updateMyMfaEnabled = async (req: Request, res: Response) => {
|
|
const { isMfaEnabled }: { isMfaEnabled: boolean } = req.body;
|
|
req.user.isMfaEnabled = isMfaEnabled;
|
|
|
|
if (isMfaEnabled) {
|
|
// TODO: adapt this route/controller
|
|
// to work for different forms of MFA
|
|
req.user.mfaMethods = ["email"];
|
|
} else {
|
|
req.user.mfaMethods = [];
|
|
}
|
|
|
|
await req.user.save();
|
|
|
|
const user = req.user;
|
|
|
|
return res.status(200).send({
|
|
user,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Update name of the current user to [firstName, lastName].
|
|
* @param req
|
|
* @param res
|
|
* @returns
|
|
*/
|
|
export const updateName = async (req: Request, res: Response) => {
|
|
const {
|
|
firstName,
|
|
lastName
|
|
}: {
|
|
firstName: string;
|
|
lastName: string;
|
|
} = req.body;
|
|
|
|
const user = await User.findByIdAndUpdate(
|
|
req.user._id.toString(),
|
|
{
|
|
firstName,
|
|
lastName: lastName ?? ""
|
|
},
|
|
{
|
|
new: true
|
|
}
|
|
);
|
|
|
|
return res.status(200).send({
|
|
user,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Update auth provider of the current user to [authProvider]
|
|
* @param req
|
|
* @param res
|
|
* @returns
|
|
*/
|
|
export const updateAuthProvider = async (req: Request, res: Response) => {
|
|
const {
|
|
authProvider
|
|
} = req.body;
|
|
|
|
if (
|
|
req.user?.authProvider === AuthProvider.OKTA_SAML
|
|
|| req.user?.authProvider === AuthProvider.AZURE_SAML
|
|
|| req.user?.authProvider === AuthProvider.JUMPCLOUD_SAML
|
|
) {
|
|
return res.status(400).send({
|
|
message: "Failed to update user authentication method because SAML SSO is enforced"
|
|
});
|
|
}
|
|
|
|
const user = await User.findByIdAndUpdate(
|
|
req.user._id.toString(),
|
|
{
|
|
authProvider
|
|
},
|
|
{
|
|
new: true
|
|
}
|
|
);
|
|
|
|
return res.status(200).send({
|
|
user
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Return organizations that the current user is part of.
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
export const getMyOrganizations = async (req: Request, res: Response) => {
|
|
/*
|
|
#swagger.summary = 'Return organizations that current user is part of'
|
|
#swagger.description = 'Return organizations that current user is part of'
|
|
|
|
#swagger.security = [{
|
|
"apiKeyAuth": []
|
|
}]
|
|
|
|
#swagger.responses[200] = {
|
|
content: {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"organizations": {
|
|
"type": "array",
|
|
"items": {
|
|
$ref: "#/components/schemas/Organization"
|
|
},
|
|
"description": "Organizations that user is part of"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
const organizations = (
|
|
await MembershipOrg.find({
|
|
user: req.user._id,
|
|
}).populate("organization")
|
|
).map((m) => m.organization);
|
|
|
|
return res.status(200).send({
|
|
organizations,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Return API keys belonging to current user.
|
|
* @param req
|
|
* @param res
|
|
* @returns
|
|
*/
|
|
export const getMyAPIKeys = async (req: Request, res: Response) => {
|
|
const apiKeyData = await APIKeyData.find({
|
|
user: req.user._id,
|
|
});
|
|
|
|
return res.status(200).send(apiKeyData);
|
|
}
|
|
|
|
/**
|
|
* Create new API key for current user.
|
|
* @param req
|
|
* @param res
|
|
* @returns
|
|
*/
|
|
export const createAPIKey = async (req: Request, res: Response) => {
|
|
const { name, expiresIn } = req.body;
|
|
|
|
const secret = crypto.randomBytes(16).toString("hex");
|
|
const secretHash = await bcrypt.hash(secret, await getSaltRounds());
|
|
|
|
const expiresAt = new Date();
|
|
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
|
|
|
|
let apiKeyData = await new APIKeyData({
|
|
name,
|
|
lastUsed: new Date(),
|
|
expiresAt,
|
|
user: req.user._id,
|
|
secretHash,
|
|
}).save();
|
|
|
|
// return api key data without sensitive data
|
|
apiKeyData = (await APIKeyData.findById(apiKeyData._id)) as any;
|
|
|
|
if (!apiKeyData) throw new Error("Failed to find API key data");
|
|
|
|
const apiKey = `ak.${apiKeyData._id.toString()}.${secret}`;
|
|
|
|
return res.status(200).send({
|
|
apiKey,
|
|
apiKeyData,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Delete API key with id [apiKeyDataId] belonging to current user
|
|
* @param req
|
|
* @param res
|
|
*/
|
|
export const deleteAPIKey = async (req: Request, res: Response) => {
|
|
const { apiKeyDataId } = req.params;
|
|
|
|
const apiKeyData = await APIKeyData.findOneAndDelete({
|
|
_id: new Types.ObjectId(apiKeyDataId),
|
|
user: req.user._id
|
|
});
|
|
|
|
return res.status(200).send({
|
|
apiKeyData
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Return active sessions (TokenVersion) belonging to user
|
|
* @param req
|
|
* @param res
|
|
* @returns
|
|
*/
|
|
export const getMySessions = async (req: Request, res: Response) => {
|
|
const tokenVersions = await TokenVersion.find({
|
|
user: req.user._id
|
|
});
|
|
|
|
return res.status(200).send(tokenVersions);
|
|
}
|
|
|
|
/**
|
|
* Revoke all active sessions belong to user
|
|
* @param req
|
|
* @param res
|
|
* @returns
|
|
*/
|
|
export const deleteMySessions = async (req: Request, res: Response) => {
|
|
await TokenVersion.updateMany({
|
|
user: req.user._id,
|
|
}, {
|
|
$inc: {
|
|
refreshVersion: 1,
|
|
accessVersion: 1,
|
|
},
|
|
});
|
|
|
|
return res.status(200).send({
|
|
message: "Successfully revoked all sessions"
|
|
});
|
|
} |