mirror of
https://github.com/Infisical/infisical.git
synced 2026-05-02 03:02:03 -04:00
Checkpoint service accounts
This commit is contained in:
@@ -7,6 +7,7 @@ import * as serviceTokenDataController from './serviceTokenDataController';
|
||||
import * as apiKeyDataController from './apiKeyDataController';
|
||||
import * as secretController from './secretController';
|
||||
import * as secretsController from './secretsController';
|
||||
import * as serviceAccountsController from './serviceAccountsController';
|
||||
import * as environmentController from './environmentController';
|
||||
import * as tagController from './tagController';
|
||||
|
||||
@@ -20,6 +21,7 @@ export {
|
||||
apiKeyDataController,
|
||||
secretController,
|
||||
secretsController,
|
||||
serviceAccountsController,
|
||||
environmentController,
|
||||
tagController
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Request, Response } from 'express';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { Types } from 'mongoose';
|
||||
import {
|
||||
MembershipOrg,
|
||||
Membership,
|
||||
Workspace
|
||||
Workspace,
|
||||
ServiceAccount
|
||||
} from '../../models';
|
||||
import { deleteMembershipOrg } from '../../helpers/membershipOrg';
|
||||
import { updateSubscriptionOrgQuantity } from '../../helpers/organization';
|
||||
@@ -260,37 +262,44 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
|
||||
}
|
||||
}
|
||||
*/
|
||||
let workspaces;
|
||||
try {
|
||||
const { organizationId } = req.params;
|
||||
const { organizationId } = req.params;
|
||||
|
||||
const workspacesSet = new Set(
|
||||
(
|
||||
await Workspace.find(
|
||||
{
|
||||
organization: organizationId
|
||||
},
|
||||
'_id'
|
||||
)
|
||||
).map((w) => w._id.toString())
|
||||
);
|
||||
const workspacesSet = new Set(
|
||||
(
|
||||
await Workspace.find(
|
||||
{
|
||||
organization: organizationId
|
||||
},
|
||||
'_id'
|
||||
)
|
||||
).map((w) => w._id.toString())
|
||||
);
|
||||
|
||||
workspaces = (
|
||||
await Membership.find({
|
||||
user: req.user._id
|
||||
}).populate('workspace')
|
||||
)
|
||||
.filter((m) => workspacesSet.has(m.workspace._id.toString()))
|
||||
.map((m) => m.workspace);
|
||||
} catch (err) {
|
||||
Sentry.setUser({ email: req.user.email });
|
||||
Sentry.captureException(err);
|
||||
return res.status(400).send({
|
||||
message: 'Failed to get organization workspaces'
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
const workspaces = (
|
||||
await Membership.find({
|
||||
user: req.user._id
|
||||
}).populate('workspace')
|
||||
)
|
||||
.filter((m) => workspacesSet.has(m.workspace._id.toString()))
|
||||
.map((m) => m.workspace);
|
||||
|
||||
return res.status(200).send({
|
||||
workspaces
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return service accounts for organization with id [organizationId]
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
export const getOrganizationServiceAccounts = async (req: Request, res: Response) => {
|
||||
const { organizationId } = req.params;
|
||||
const serviceAccounts = await ServiceAccount.find({
|
||||
organization: new Types.ObjectId(organizationId)
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
serviceAccounts
|
||||
});
|
||||
}
|
||||
178
backend/src/controllers/v2/serviceAccountsController.ts
Normal file
178
backend/src/controllers/v2/serviceAccountsController.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { Types } from 'mongoose';
|
||||
import {
|
||||
ServiceAccount,
|
||||
ServiceAccountKey,
|
||||
ServiceAccountPermission
|
||||
} from '../../models';
|
||||
import {
|
||||
CreateServiceAccountDto
|
||||
} from '../../interfaces/serviceAccounts/dto';
|
||||
|
||||
/**
|
||||
* Create a new service account under organization with id [organizationId]
|
||||
* that has access to workspaces [workspaces]
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
export const createServiceAccount = async (req: Request, res: Response) => {
|
||||
const {
|
||||
organizationId,
|
||||
name,
|
||||
publicKey,
|
||||
expiresIn,
|
||||
}: CreateServiceAccountDto = req.body;
|
||||
|
||||
let expiresAt;
|
||||
if (expiresIn) {
|
||||
expiresAt = new Date();
|
||||
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
|
||||
}
|
||||
|
||||
const serviceAccount = await new ServiceAccount({
|
||||
name,
|
||||
organization: new Types.ObjectId(organizationId),
|
||||
user: req.user,
|
||||
publicKey,
|
||||
expiresAt
|
||||
}).save();
|
||||
|
||||
// await Promise.all(
|
||||
// workspaces.map(async ({
|
||||
// workspaceId,
|
||||
// environments,
|
||||
// permissions,
|
||||
// encryptedKey,
|
||||
// nonce
|
||||
// }: {
|
||||
// workspaceId: string;
|
||||
// environments: string[];
|
||||
// permissions: string[];
|
||||
// encryptedKey: string;
|
||||
// nonce: string;
|
||||
// }) => {
|
||||
// const serviceAccountKey = await new ServiceAccountKey({
|
||||
// encryptedKey,
|
||||
// nonce,
|
||||
// sender: req.user._id,
|
||||
// serviceAccount: serviceAccount._id,
|
||||
// workspace: new Types.ObjectId(workspaceId)
|
||||
// });
|
||||
|
||||
// console.log('serviceAccountKey: ', serviceAccountKey);
|
||||
|
||||
// await Promise.all(
|
||||
// permissions.map(async (name: string) => {
|
||||
// const permission = await new ServiceAccountPermission({
|
||||
// serviceAccount: serviceAccount._id,
|
||||
// name,
|
||||
// workspace: new Types.ObjectId(workspaceId),
|
||||
// environments
|
||||
// }).save();
|
||||
|
||||
// console.log('permission: ', permission);
|
||||
// })
|
||||
// );
|
||||
// })
|
||||
// );
|
||||
|
||||
return res.status(200).send({
|
||||
serviceAccount
|
||||
});
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Add a service account key to service account with id [serviceAccountId]
|
||||
// * for workspace with id [workspaceId]
|
||||
// * @param req
|
||||
// * @param res
|
||||
// * @returns
|
||||
// */
|
||||
// export const addServiceAccountKey = async (req: Request, res: Response) => {
|
||||
// const {
|
||||
// workspaceId,
|
||||
// encryptedKey,
|
||||
// nonce
|
||||
// } = req.body;
|
||||
|
||||
// const serviceAccountKey = await new ServiceAccountKey({
|
||||
// encryptedKey,
|
||||
// nonce,
|
||||
// sender: req.user._id,
|
||||
// serviceAccount: req.serviceAccount._d,
|
||||
// workspace: new Types.ObjectId(workspaceId)
|
||||
// }).save();
|
||||
|
||||
// return serviceAccountKey;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Delete service account with id [serviceAccountId]
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
export const deleteServiceAccount = async (req: Request, res: Response) => {
|
||||
const { serviceAccountId } = req.params;
|
||||
|
||||
const serviceAccount = await ServiceAccount.findByIdAndDelete(serviceAccountId);
|
||||
|
||||
await ServiceAccountKey.deleteMany({
|
||||
serviceAccount: new Types.ObjectId(serviceAccountId)
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
serviceAccount
|
||||
});
|
||||
}
|
||||
|
||||
export const addServiceAccountWorkspaceAccess = async (req: Request, res: Response) => {
|
||||
const { serviceAccountId, workspaceId } = req.params;
|
||||
const {
|
||||
encryptedKey,
|
||||
nonce,
|
||||
permissions // should contain environments
|
||||
} = req.body;
|
||||
|
||||
const serviceAccountKey = await new ServiceAccountKey({
|
||||
encryptedKey,
|
||||
nonce,
|
||||
sender: req.user._id,
|
||||
serviceAccount: req.serviceAccount._id,
|
||||
workspace: new Types.ObjectId('workspaceId')
|
||||
});
|
||||
|
||||
const serviceAccountPermissions = await Promise.all(
|
||||
permissions.map
|
||||
);
|
||||
}
|
||||
|
||||
export const deleteServiceAccountWorkspaceAccess = async (req: Request, res: Response) => {
|
||||
// TODO
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Add a service account key to service account with id [serviceAccountId]
|
||||
// * for workspace with id [workspaceId]
|
||||
// * @param req
|
||||
// * @param res
|
||||
// * @returns
|
||||
// */
|
||||
// export const addServiceAccountKey = async (req: Request, res: Response) => {
|
||||
// const {
|
||||
// workspaceId,
|
||||
// encryptedKey,
|
||||
// nonce
|
||||
// } = req.body;
|
||||
|
||||
// const serviceAccountKey = await new ServiceAccountKey({
|
||||
// encryptedKey,
|
||||
// nonce,
|
||||
// sender: req.user._id,
|
||||
// serviceAccount: req.serviceAccount._d,
|
||||
// workspace: new Types.ObjectId(workspaceId)
|
||||
// }).save();
|
||||
|
||||
// return serviceAccountKey;
|
||||
// }
|
||||
@@ -56,6 +56,7 @@ import {
|
||||
secret as v2SecretRouter, // begin to phase out
|
||||
secrets as v2SecretsRouter,
|
||||
serviceTokenData as v2ServiceTokenDataRouter,
|
||||
serviceAccounts as v2ServiceAccountsRouter,
|
||||
apiKeyData as v2APIKeyDataRouter,
|
||||
environment as v2EnvironmentRouter,
|
||||
tags as v2TagsRouter,
|
||||
@@ -148,6 +149,7 @@ const main = async () => {
|
||||
app.use('/api/v2/secret', v2SecretRouter); // deprecated
|
||||
app.use('/api/v2/secrets', v2SecretsRouter);
|
||||
app.use('/api/v2/service-token', v2ServiceTokenDataRouter); // TODO: turn into plural route
|
||||
app.use('/api/v2/service-accounts', v2ServiceAccountsRouter); // new
|
||||
app.use('/api/v2/api-key', v2APIKeyDataRouter);
|
||||
|
||||
// api docs
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
interface CreateServiceAccountDto {
|
||||
organizationId: string;
|
||||
name: string;
|
||||
publicKey: string;
|
||||
expiresIn: number;
|
||||
}
|
||||
|
||||
export default CreateServiceAccountDto;
|
||||
5
backend/src/interfaces/serviceAccounts/dto/index.ts
Normal file
5
backend/src/interfaces/serviceAccounts/dto/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import CreateServiceAccountDto from './CreateServiceAccountDto';
|
||||
|
||||
export {
|
||||
CreateServiceAccountDto
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import requireIntegrationAuth from './requireIntegrationAuth';
|
||||
import requireIntegrationAuthorizationAuth from './requireIntegrationAuthorizationAuth';
|
||||
import requireServiceTokenAuth from './requireServiceTokenAuth';
|
||||
import requireServiceTokenDataAuth from './requireServiceTokenDataAuth';
|
||||
import requireServiceAccountAuth from './requireServiceAccountAuth';
|
||||
import requireSecretAuth from './requireSecretAuth';
|
||||
import requireSecretsAuth from './requireSecretsAuth';
|
||||
import validateRequest from './validateRequest';
|
||||
@@ -27,6 +28,7 @@ export {
|
||||
requireIntegrationAuthorizationAuth,
|
||||
requireServiceTokenAuth,
|
||||
requireServiceTokenDataAuth,
|
||||
requireServiceAccountAuth,
|
||||
requireSecretAuth,
|
||||
requireSecretsAuth,
|
||||
validateRequest
|
||||
|
||||
@@ -2,6 +2,8 @@ import { Request, Response, NextFunction } from 'express';
|
||||
import { IOrganization, MembershipOrg } from '../models';
|
||||
import { UnauthorizedRequestError, ValidationError } from '../utils/errors';
|
||||
|
||||
type req = 'params' | 'body' | 'query';
|
||||
|
||||
/**
|
||||
* Validate if user on request is a member with proper roles for organization
|
||||
* on request params.
|
||||
@@ -11,18 +13,22 @@ import { UnauthorizedRequestError, ValidationError } from '../utils/errors';
|
||||
*/
|
||||
const requireOrganizationAuth = ({
|
||||
acceptedRoles,
|
||||
acceptedStatuses
|
||||
acceptedStatuses,
|
||||
location = 'params'
|
||||
}: {
|
||||
acceptedRoles: string[];
|
||||
acceptedStatuses: string[];
|
||||
location?: req;
|
||||
}) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
// organization authorization middleware
|
||||
|
||||
const { organizationId } = req[location];
|
||||
|
||||
// validate organization membership
|
||||
const membershipOrg = await MembershipOrg.findOne({
|
||||
user: req.user._id,
|
||||
organization: req.params.organizationId
|
||||
organization: organizationId
|
||||
}).populate<{ organization: IOrganization }>('organization');
|
||||
|
||||
|
||||
|
||||
39
backend/src/middleware/requireServiceAccountAuth.ts
Normal file
39
backend/src/middleware/requireServiceAccountAuth.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { ServiceAccount } from '../models';
|
||||
import {
|
||||
AccountNotFoundError,
|
||||
UnauthorizedRequestError
|
||||
} from '../utils/errors';
|
||||
|
||||
type req = 'params' | 'body' | 'query';
|
||||
|
||||
const requireServiceAccountAuth = ({
|
||||
acceptedRoles,
|
||||
acceptedStatuses,
|
||||
location = 'params'
|
||||
}: {
|
||||
acceptedRoles: string[];
|
||||
acceptedStatuses: string[];
|
||||
location?: req;
|
||||
}) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
const serviceAccountId = req[location].serviceAccountId;
|
||||
const serviceAccount = await ServiceAccount.findById(serviceAccountId);
|
||||
|
||||
// TODO: acceptedRoles and acceptedStatuses
|
||||
|
||||
if (!serviceAccount) {
|
||||
return next(AccountNotFoundError({ message: 'Failed to locate Service Account' }));
|
||||
}
|
||||
|
||||
if (serviceAccount.user.toString() !== req.user.id.toString()) {
|
||||
return next(UnauthorizedRequestError({ message: 'Failed to authenticate the Service Account' }));
|
||||
}
|
||||
|
||||
req.serviceAccount = serviceAccount;
|
||||
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
export default requireServiceAccountAuth;
|
||||
@@ -10,6 +10,9 @@ import MembershipOrg, { IMembershipOrg } from './membershipOrg';
|
||||
import Organization, { IOrganization } from './organization';
|
||||
import Secret, { ISecret } from './secret';
|
||||
import ServiceToken, { IServiceToken } from './serviceToken';
|
||||
import ServiceAccount, { IServiceAccount } from './serviceAccount'; // new
|
||||
import ServiceAccountKey, { IServiceAccountKey } from './serviceAccountKey'; // new
|
||||
import ServiceAccountPermission, { IServiceAccountPermission } from './serviceAccountPermission';
|
||||
import TokenData, { ITokenData } from './tokenData';
|
||||
import User, { IUser } from './user';
|
||||
import UserAction, { IUserAction } from './userAction';
|
||||
@@ -43,6 +46,12 @@ export {
|
||||
ISecret,
|
||||
ServiceToken,
|
||||
IServiceToken,
|
||||
ServiceAccount,
|
||||
IServiceAccount,
|
||||
ServiceAccountKey,
|
||||
IServiceAccountKey,
|
||||
ServiceAccountPermission,
|
||||
IServiceAccountPermission,
|
||||
TokenData,
|
||||
ITokenData,
|
||||
User,
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { Schema, model, Types, Document } from 'mongoose';
|
||||
|
||||
export interface IPermission extends Document {
|
||||
_id: Types.ObjectId;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const permissionSchema = new Schema<IPermission>(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true
|
||||
}
|
||||
);
|
||||
|
||||
const Permission = model<IPermission>('Permission', permissionSchema);
|
||||
|
||||
export default Permission;
|
||||
@@ -3,9 +3,8 @@ import { Schema, model, Types, Document } from 'mongoose';
|
||||
export interface IServiceAccount extends Document {
|
||||
_id: Types.ObjectId;
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
organization: Types.ObjectId;
|
||||
createdBy: Types.ObjectId;
|
||||
user: Types.ObjectId;
|
||||
publicKey: string;
|
||||
expiresAt: Date;
|
||||
}
|
||||
@@ -16,16 +15,12 @@ const serviceAccountSchema = new Schema<IServiceAccount>(
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
organization: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'Organization',
|
||||
required: true
|
||||
},
|
||||
createdBy: {
|
||||
user: { // user who created the service account
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'User',
|
||||
required: true
|
||||
|
||||
@@ -9,7 +9,7 @@ export interface IServiceAccountKey {
|
||||
workspace: Types.ObjectId;
|
||||
}
|
||||
|
||||
const serviceAccountSchema = new Schema<IServiceAccountKey>(
|
||||
const serviceAccountKeySchema = new Schema<IServiceAccountKey>(
|
||||
{
|
||||
encryptedKey: {
|
||||
type: String,
|
||||
@@ -39,6 +39,6 @@ const serviceAccountSchema = new Schema<IServiceAccountKey>(
|
||||
}
|
||||
);
|
||||
|
||||
const ServiceAccountKey = model<IServiceAccountKey>('ServiceAccountKey', serviceAccountSchema);
|
||||
const ServiceAccountKey = model<IServiceAccountKey>('ServiceAccountKey', serviceAccountKeySchema);
|
||||
|
||||
export default ServiceAccountKey;
|
||||
|
||||
37
backend/src/models/serviceAccountPermission.ts
Normal file
37
backend/src/models/serviceAccountPermission.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Schema, model, Types, Document } from 'mongoose';
|
||||
|
||||
export interface IServiceAccountPermission extends Document {
|
||||
_id: Types.ObjectId;
|
||||
serviceAccount: Types.ObjectId;
|
||||
name: string;
|
||||
workspace?: Types.ObjectId;
|
||||
environment?: string;
|
||||
}
|
||||
|
||||
const serviceAccountPermissionSchema = new Schema<IServiceAccountPermission>(
|
||||
{
|
||||
serviceAccount: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'ServiceAccount',
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
workspace: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'Workspace',
|
||||
},
|
||||
environment: {
|
||||
type: 'String'
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true
|
||||
}
|
||||
);
|
||||
|
||||
const ServiceAccountPermission = model<IServiceAccountPermission>('ServiceAccountPermission', serviceAccountPermissionSchema);
|
||||
|
||||
export default ServiceAccountPermission;
|
||||
@@ -6,6 +6,7 @@ import workspace from './workspace';
|
||||
import secret from './secret'; // deprecated
|
||||
import secrets from './secrets';
|
||||
import serviceTokenData from './serviceTokenData';
|
||||
import serviceAccounts from './serviceAccounts';
|
||||
import apiKeyData from './apiKeyData';
|
||||
import environment from "./environment"
|
||||
import tags from "./tags"
|
||||
@@ -19,6 +20,7 @@ export {
|
||||
secret,
|
||||
secrets,
|
||||
serviceTokenData,
|
||||
serviceAccounts,
|
||||
apiKeyData,
|
||||
environment,
|
||||
tags
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
requireMembershipOrgAuth,
|
||||
validateRequest
|
||||
} from '../../middleware';
|
||||
import { body, param, query } from 'express-validator';
|
||||
import { body, param } from 'express-validator';
|
||||
import { OWNER, ADMIN, MEMBER, ACCEPTED } from '../../variables';
|
||||
import { organizationsController } from '../../controllers/v2';
|
||||
|
||||
@@ -77,4 +77,18 @@ router.get(
|
||||
organizationsController.getOrganizationWorkspaces
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/:organizationId/service-accounts',
|
||||
param('organizationId').exists().trim(),
|
||||
validateRequest,
|
||||
requireAuth({
|
||||
acceptedAuthModes: ['jwt']
|
||||
}),
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN],
|
||||
acceptedStatuses: [ACCEPTED]
|
||||
}),
|
||||
organizationsController.getOrganizationServiceAccounts
|
||||
);
|
||||
|
||||
export default router;
|
||||
53
backend/src/routes/v2/serviceAccounts.ts
Normal file
53
backend/src/routes/v2/serviceAccounts.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import express from 'express';
|
||||
const router = express.Router();
|
||||
import {
|
||||
requireOrganizationAuth,
|
||||
requireServiceAccountAuth
|
||||
} from '../../middleware';
|
||||
import { body } from 'express-validator';
|
||||
import {
|
||||
OWNER,
|
||||
ADMIN,
|
||||
MEMBER,
|
||||
ACCEPTED
|
||||
} from '../../variables';
|
||||
import { serviceAccountsController } from '../../controllers/v2';
|
||||
|
||||
router.post(
|
||||
'/',
|
||||
body('organizationId').exists().isString().trim(),
|
||||
body('name').exists().isString().trim(),
|
||||
body('publicKey').exists().isString().trim(),
|
||||
body('expiresIn'), // measured in ms
|
||||
requireOrganizationAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
acceptedStatuses: [ACCEPTED],
|
||||
location: 'body'
|
||||
}),
|
||||
serviceAccountsController.createServiceAccount
|
||||
);
|
||||
|
||||
// router.post(
|
||||
// '/:serviceAccountId/key',
|
||||
// body('workspaceId').exists().isString().trim(),
|
||||
// body('encryptedKey').exists().isString().trim(),
|
||||
// body('nonce').exists().isString().trim(),
|
||||
// requireServiceAccountAuth({
|
||||
// acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
// acceptedStatuses: [ACCEPTED]
|
||||
// }),
|
||||
// serviceAccountsController.addServiceAccountKey
|
||||
// );
|
||||
|
||||
router.delete(
|
||||
'/:serviceAccountId/key/:serviceAccountKeyId',
|
||||
requireServiceAccountAuth({
|
||||
acceptedRoles: [OWNER, ADMIN, MEMBER],
|
||||
acceptedStatuses: [ACCEPTED]
|
||||
}),
|
||||
async (req, res) => {
|
||||
// TODO: delete service account key id
|
||||
}
|
||||
);
|
||||
|
||||
export default router;
|
||||
1
backend/src/types/express/index.d.ts
vendored
1
backend/src/types/express/index.d.ts
vendored
@@ -19,6 +19,7 @@ declare global {
|
||||
secrets: any;
|
||||
secretSnapshot: any;
|
||||
serviceToken: any;
|
||||
serviceAccount: any;
|
||||
accessToken: any;
|
||||
serviceTokenData: any;
|
||||
apiKeyData: any;
|
||||
|
||||
Reference in New Issue
Block a user