Finish basic scaffolding for service token v3

This commit is contained in:
Tuan Dang
2023-09-20 17:32:33 +01:00
parent 1cdd840485
commit 1896442168
25 changed files with 756 additions and 101 deletions
+2
View File
@@ -2,10 +2,12 @@ import * as secretsController from "./secretsController";
import * as workspacesController from "./workspacesController";
import * as authController from "./authController";
import * as signupController from "./signupController";
import * as serviceTokenDataController from "./serviceTokenDataController";
export {
authController,
secretsController,
signupController,
workspacesController,
serviceTokenDataController
}
@@ -0,0 +1,70 @@
import { Request, Response } from "express";
import { Types } from "mongoose";
import { ServiceTokenDataV3 } from "../../models";
import { validateRequest } from "../../helpers/validation";
import * as reqValidator from "../../validation/serviceTokenV3";
import { createToken } from "../../helpers/auth";
export const createServiceTokenData = async (req: Request, res: Response) => {
const {
body: { name, workspaceId, publicKey }
} = await validateRequest(reqValidator.CreateServiceTokenV3, req);
const serviceTokenData = await new ServiceTokenDataV3({
name,
workspace: new Types.ObjectId(workspaceId),
publicKey,
isActive: false
}).save();
console.log("the newly created serviceTokenDataV3: ", serviceTokenData);
const token = createToken({
payload: {
_id: serviceTokenData._id.toString()
},
expiresIn: "5d",
secret: "hello" // TODO: replace with real secret
});
console.log("jwt token: ", token);
return res.status(200).send({
serviceTokenData,
serviceToken: `proj_token.${token}`
});
}
export const updateServiceTokenData = async (req: Request, res: Response) => {
const {
params: { serviceTokenDataId },
body: { name, isActive }
} = await validateRequest(reqValidator.UpdateServiceTokenV3, req);
const serviceTokenData = await ServiceTokenDataV3.findByIdAndUpdate(
serviceTokenDataId,
{
name,
isActive
},
{
new: true
}
);
return res.status(200).send({
serviceTokenData
});
}
export const deleteServiceTokenData = async (req: Request, res: Response) => {
const {
params: { serviceTokenDataId }
} = await validateRequest(reqValidator.DeleteServiceTokenV3, req);
const serviceTokenData = await ServiceTokenDataV3.findByIdAndDelete(serviceTokenDataId);
return res.status(200).send({
serviceTokenData
});
}
@@ -1,7 +1,7 @@
import { Request, Response } from "express";
import { Types } from "mongoose";
import { validateRequest } from "../../helpers/validation";
import { Secret } from "../../models";
import { Secret, ServiceTokenDataV3 } from "../../models";
import { SecretService } from "../../services";
import { getUserProjectPermissions } from "../../ee/services/ProjectRoleService";
import { UnauthorizedRequestError } from "../../utils/errors";
@@ -101,3 +101,17 @@ export const nameWorkspaceSecrets = async (req: Request, res: Response) => {
message: "Successfully named workspace secrets"
});
};
export const getWorkspaceServiceTokenData = async (req: Request, res: Response) => {
const {
params: { workspaceId }
} = await validateRequest(reqValidator.GetWorkspaceServiceTokenDataV3, req);
const serviceTokenData = await ServiceTokenDataV3.find({
workspace: new Types.ObjectId(workspaceId)
});
return res.status(200).send({
serviceTokenData
});
}
+3 -1
View File
@@ -30,6 +30,7 @@ router.get(
router.get("/redirect/github", authLimiter, (req, res, next) => {
passport.authenticate("github", {
session: false,
scope: [ 'user:email' ],
...(req.query.callback_port
? {
state: req.query.callback_port as string
@@ -43,7 +44,8 @@ router.get(
authLimiter,
passport.authenticate("github", {
failureRedirect: "/login/provider/error",
session: false
session: false,
scope: [ 'user:email' ]
}),
ssoController.redirectSSO
);
+5 -2
View File
@@ -65,7 +65,8 @@ import {
auth as v3AuthRouter,
secrets as v3SecretsRouter,
signup as v3SignupRouter,
workspaces as v3WorkspacesRouter
workspaces as v3WorkspacesRouter,
serviceTokenData as v3ServiceTokenDataRouter
} from "./routes/v3";
import { healthCheck } from "./routes/status";
import { getLogger } from "./utils/logger";
@@ -188,13 +189,15 @@ const main = async () => {
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/service-token", v2ServiceTokenDataRouter);
app.use("/api/v2/service-accounts", v2ServiceAccountsRouter); // new
// app.use("/api/v2/service-accounts", v2ServiceAccountsRouter); // new
// v3 routes (experimental)
app.use("/api/v3/auth", v3AuthRouter);
app.use("/api/v3/secrets", v3SecretsRouter);
app.use("/api/v3/workspaces", v3WorkspacesRouter);
app.use("/api/v3/signup", v3SignupRouter);
app.use("/api/v3/service-token", v3ServiceTokenDataRouter);
// api docs
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerFile));
+8 -7
View File
@@ -14,17 +14,18 @@ export * from "./tag";
export * from "./folder";
export * from "./secretImports";
export * from "./secretBlindIndexData";
export * from "./serviceToken";
export * from "./serviceAccount";
export * from "./serviceAccountKey";
export * from "./serviceAccountOrganizationPermission";
export * from "./serviceAccountWorkspacePermission";
export * from "./serviceToken"; // TODO: deprecate
export * from "./serviceAccount"; // TODO: deprecate
export * from "./serviceAccountKey"; // TODO: deprecate
export * from "./serviceAccountOrganizationPermission"; // TODO: deprecate
export * from "./serviceAccountWorkspacePermission"; // TODO: deprecate
export * from "./tokenData";
export * from "./user";
export * from "./userAction";
export * from "./workspace";
export * from "./serviceTokenData";
export * from "./serviceTokenData"; // TODO: deprecate
export * from "./apiKeyData";
export * from "./loginSRPDetail";
export * from "./tokenVersion";
export * from "./webhooks";
export * from "./webhooks";
export * from "./serviceTokenDataV3";
@@ -1,13 +1,15 @@
import { Document, Schema, Types, model } from "mongoose";
export interface IServiceTokenV3 extends Document {
export interface IServiceTokenDataV3 extends Document {
_id: Types.ObjectId;
name: string;
workspace: Types.ObjectId;
publicKey: string;
isActive: boolean;
lastUsed: Date;
}
const serviceTokenV3Schema = new Schema(
const serviceTokenDataV3Schema = new Schema(
{
name: {
type: String,
@@ -21,8 +23,19 @@ const serviceTokenV3Schema = new Schema(
publicKey: {
type: String,
required: true
},
isActive: {
type: Boolean,
required: true
},
lastUsed: {
type: Date,
required: false
}
},
{
timestamps: true
}
);
export const ServiceTokenV3 = model<IServiceTokenV3>("ServiceTokenV3", serviceTokenV3Schema);
export const ServiceTokenDataV3 = model<IServiceTokenDataV3>("ServiceTokenDataV3", serviceTokenDataV3Schema);
+2
View File
@@ -2,10 +2,12 @@ import auth from "./auth";
import secrets from "./secrets";
import workspaces from "./workspaces";
import signup from "./signup";
import serviceTokenData from "./serviceTokenData";
export {
auth,
secrets,
signup,
workspaces,
serviceTokenData
}
+31
View File
@@ -0,0 +1,31 @@
import express from "express";
const router = express.Router();
import { requireAuth } from "../../middleware";
import { AuthMode } from "../../variables";
import { serviceTokenDataController } from "../../controllers/v3";
router.post(
"/",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
serviceTokenDataController.createServiceTokenData
);
router.patch(
"/:serviceTokenDataId",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
serviceTokenDataController.updateServiceTokenData
);
router.delete(
"/:serviceTokenDataId",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
serviceTokenDataController.deleteServiceTokenData
);
export default router;
+8
View File
@@ -34,4 +34,12 @@ router.post(
// --
router.get(
"/:workspaceId/service-token",
requireAuth({
acceptedAuthModes: [AuthMode.JWT]
}),
workspacesController.getWorkspaceServiceTokenData
);
export default router;
+5 -1
View File
@@ -24,6 +24,8 @@ import { InternalServerError, OrganizationNotFoundError } from "./errors";
import { ACCEPTED, INVITED, MEMBER } from "../variables";
import { getSiteURL } from "../config";
import { standardRequest } from "../config/request";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const GoogleStrategy = require("passport-google-oauth20").Strategy;
// eslint-disable-next-line @typescript-eslint/no-var-requires
@@ -143,9 +145,11 @@ const initializePassport = async () => {
passReqToCallback: true,
clientID: clientIdGitHubLogin,
clientSecret: clientSecretGitHubLogin,
callbackURL: "/api/v1/sso/github"
callbackURL: "/api/v1/sso/github",
scope: [ 'user:email' ]
},
async (req : express.Request, accessToken : any, refreshToken : any, profile : any, done : any) => {
const email = profile.emails[0].value;
let user = await User.findOne({
+1
View File
@@ -9,3 +9,4 @@ export * from "./organization";
export * from "./secrets";
export * from "./serviceAccount";
export * from "./serviceTokenData";
export * from "./serviceTokenV3";
+25
View File
@@ -0,0 +1,25 @@
import { z } from "zod";
export const CreateServiceTokenV3 = z.object({
body: z.object({
name: z.string().trim(),
workspaceId: z.string().trim(),
publicKey: z.string().trim(),
})
});
export const UpdateServiceTokenV3 = z.object({
params: z.object({
serviceTokenDataId: z.string()
}),
body: z.object({
name: z.string().trim().optional(),
isActive: z.boolean().optional()
})
});
export const DeleteServiceTokenV3 = z.object({
params: z.object({
serviceTokenDataId: z.string()
}),
});
+6
View File
@@ -299,3 +299,9 @@ export const NameWorkspaceSecretsV3 = z.object({
.array()
})
});
export const GetWorkspaceServiceTokenDataV3 = z.object({
params: z.object({
workspaceId: z.string().trim()
})
});