mirror of
https://github.com/Infisical/infisical.git
synced 2026-01-10 16:08:20 -05:00
222 lines
5.1 KiB
TypeScript
222 lines
5.1 KiB
TypeScript
import { Request, Response } from 'express';
|
|
import * as Sentry from '@sentry/node';
|
|
import {
|
|
Workspace,
|
|
Membership,
|
|
MembershipOrg,
|
|
Integration,
|
|
IntegrationAuth,
|
|
Key,
|
|
IUser,
|
|
ServiceToken,
|
|
ServiceTokenData
|
|
} from '../../models';
|
|
import {
|
|
v2PushSecrets as push,
|
|
pullSecrets as pull,
|
|
reformatPullSecrets
|
|
} from '../../helpers/secret';
|
|
import { pushKeys } from '../../helpers/key';
|
|
import { postHogClient, EventService } from '../../services';
|
|
import { eventPushSecrets } from '../../events';
|
|
|
|
interface V2PushSecret {
|
|
type: string; // personal or shared
|
|
secretKeyCiphertext: string;
|
|
secretKeyIV: string;
|
|
secretKeyTag: string;
|
|
secretKeyHash: string;
|
|
secretValueCiphertext: string;
|
|
secretValueIV: string;
|
|
secretValueTag: string;
|
|
secretValueHash: string;
|
|
secretCommentCiphertext?: string;
|
|
secretCommentIV?: string;
|
|
secretCommentTag?: string;
|
|
secretCommentHash?: string;
|
|
}
|
|
|
|
/**
|
|
* Upload (encrypted) secrets to workspace with id [workspaceId]
|
|
* for environment [environment]
|
|
* @param req
|
|
* @param res
|
|
* @returns
|
|
*/
|
|
export const pushWorkspaceSecrets = async (req: Request, res: Response) => {
|
|
// upload (encrypted) secrets to workspace with id [workspaceId]
|
|
try {
|
|
let { secrets }: { secrets: V2PushSecret[] } = req.body;
|
|
const { keys, environment, channel } = req.body;
|
|
const { workspaceId } = req.params;
|
|
|
|
// validate environment
|
|
const workspaceEnvs = req.membership.workspace.environments;
|
|
if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) {
|
|
throw new Error('Failed to validate environment');
|
|
}
|
|
|
|
// sanitize secrets
|
|
secrets = secrets.filter(
|
|
(s: V2PushSecret) => s.secretKeyCiphertext !== '' && s.secretValueCiphertext !== ''
|
|
);
|
|
|
|
await push({
|
|
userId: req.user._id,
|
|
workspaceId,
|
|
environment,
|
|
secrets,
|
|
channel: channel ? channel : 'cli',
|
|
ipAddress: req.ip
|
|
});
|
|
|
|
await pushKeys({
|
|
userId: req.user._id,
|
|
workspaceId,
|
|
keys
|
|
});
|
|
|
|
if (postHogClient) {
|
|
postHogClient.capture({
|
|
event: 'secrets pushed',
|
|
distinctId: req.user.email,
|
|
properties: {
|
|
numberOfSecrets: secrets.length,
|
|
environment,
|
|
workspaceId,
|
|
channel: channel ? channel : 'cli'
|
|
}
|
|
});
|
|
}
|
|
|
|
// trigger event - push secrets
|
|
EventService.handleEvent({
|
|
event: eventPushSecrets({
|
|
workspaceId
|
|
})
|
|
});
|
|
|
|
} catch (err) {
|
|
Sentry.setUser({ email: req.user.email });
|
|
Sentry.captureException(err);
|
|
return res.status(400).send({
|
|
message: 'Failed to upload workspace secrets'
|
|
});
|
|
}
|
|
|
|
return res.status(200).send({
|
|
message: 'Successfully uploaded workspace secrets'
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Return (encrypted) secrets for workspace with id [workspaceId]
|
|
* for environment [environment]
|
|
* @param req
|
|
* @param res
|
|
* @returns
|
|
*/
|
|
export const pullSecrets = async (req: Request, res: Response) => {
|
|
let secrets;
|
|
try {
|
|
const environment: string = req.query.environment as string;
|
|
const channel: string = req.query.channel as string;
|
|
const { workspaceId } = req.params;
|
|
|
|
let userId;
|
|
if (req.user) {
|
|
userId = req.user._id.toString();
|
|
} else if (req.serviceTokenData) {
|
|
userId = req.serviceTokenData.user._id
|
|
}
|
|
// validate environment
|
|
const workspaceEnvs = req.membership.workspace.environments;
|
|
if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) {
|
|
throw new Error('Failed to validate environment');
|
|
}
|
|
|
|
secrets = await pull({
|
|
userId,
|
|
workspaceId,
|
|
environment,
|
|
channel: channel ? channel : 'cli',
|
|
ipAddress: req.ip
|
|
});
|
|
|
|
if (channel !== 'cli') {
|
|
secrets = reformatPullSecrets({ secrets });
|
|
}
|
|
|
|
if (postHogClient) {
|
|
// capture secrets pushed event in production
|
|
postHogClient.capture({
|
|
distinctId: req.user.email,
|
|
event: 'secrets pulled',
|
|
properties: {
|
|
numberOfSecrets: secrets.length,
|
|
environment,
|
|
workspaceId,
|
|
channel: channel ? channel : 'cli'
|
|
}
|
|
});
|
|
}
|
|
} catch (err) {
|
|
Sentry.setUser({ email: req.user.email });
|
|
Sentry.captureException(err);
|
|
return res.status(400).send({
|
|
message: 'Failed to pull workspace secrets'
|
|
});
|
|
}
|
|
|
|
return res.status(200).send({
|
|
secrets
|
|
});
|
|
};
|
|
|
|
export const getWorkspaceKey = async (req: Request, res: Response) => {
|
|
let key;
|
|
try {
|
|
const { workspaceId } = req.params;
|
|
|
|
key = await Key.findOne({
|
|
workspace: workspaceId,
|
|
receiver: req.user._id
|
|
}).populate('sender', '+publicKey');
|
|
|
|
if (!key) throw new Error('Failed to find workspace key');
|
|
} catch (err) {
|
|
Sentry.setUser({ email: req.user.email });
|
|
Sentry.captureException(err);
|
|
return res.status(400).send({
|
|
message: 'Failed to get workspace key'
|
|
});
|
|
}
|
|
|
|
return res.status(200).json(key);
|
|
}
|
|
export const getWorkspaceServiceTokenData = async (
|
|
req: Request,
|
|
res: Response
|
|
) => {
|
|
let serviceTokenData;
|
|
try {
|
|
const { workspaceId } = req.params;
|
|
|
|
serviceTokenData = await ServiceTokenData
|
|
.find({
|
|
workspace: workspaceId
|
|
})
|
|
.select('+encryptedKey +iv +tag');
|
|
|
|
} catch (err) {
|
|
Sentry.setUser({ email: req.user.email });
|
|
Sentry.captureException(err);
|
|
return res.status(400).send({
|
|
message: 'Failed to get workspace service token data'
|
|
});
|
|
}
|
|
|
|
return res.status(200).send({
|
|
serviceTokenData
|
|
});
|
|
} |