mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 05:19:49 +00:00
Merge remote-tracking branch 'origin' into org-based-auth
This commit is contained in:
@@ -1,10 +1,18 @@
|
||||
import knex from "knex";
|
||||
|
||||
export type TDbClient = ReturnType<typeof initDbConnection>;
|
||||
export const initDbConnection = (dbConnectionUri: string) => {
|
||||
export const initDbConnection = ({ dbConnectionUri, dbRootCert }: { dbConnectionUri: string; dbRootCert?: string }) => {
|
||||
const db = knex({
|
||||
client: "pg",
|
||||
connection: dbConnectionUri
|
||||
connection: {
|
||||
connectionString: dbConnectionUri,
|
||||
ssl: dbRootCert
|
||||
? {
|
||||
rejectUnauthorized: true,
|
||||
ca: Buffer.from(dbRootCert, "base64").toString("ascii")
|
||||
}
|
||||
: false
|
||||
}
|
||||
});
|
||||
|
||||
return db;
|
||||
|
||||
@@ -91,7 +91,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
||||
// eslint-disable-next-line
|
||||
async (req, profile, cb) => {
|
||||
try {
|
||||
const serverCfg = getServerCfg();
|
||||
const serverCfg = await getServerCfg();
|
||||
if (!profile) throw new BadRequestError({ message: "Missing profile" });
|
||||
const { firstName } = profile;
|
||||
const email = profile?.email ?? (profile?.emailAddress as string); // emailRippling is added because in Rippling the field `email` reserved
|
||||
|
||||
@@ -15,9 +15,11 @@ const envSchema = z
|
||||
PORT: z.coerce.number().default(4000),
|
||||
REDIS_URL: zpStr(z.string()),
|
||||
HOST: zpStr(z.string().default("localhost")),
|
||||
DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database conntection string")),
|
||||
DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database connection string")),
|
||||
DB_ROOT_CERT: zpStr(z.string().describe("Postgres database base64-encoded CA cert").optional()),
|
||||
NODE_ENV: z.enum(["development", "test", "production"]).default("production"),
|
||||
SALT_ROUNDS: z.coerce.number().default(10),
|
||||
INITIAL_ORGANIZATION_NAME: zpStr(z.string().optional()),
|
||||
// TODO(akhilmhdh): will be changed to one
|
||||
ENCRYPTION_KEY: zpStr(z.string().optional()),
|
||||
ROOT_ENCRYPTION_KEY: zpStr(z.string().optional()),
|
||||
|
||||
+6
-2
@@ -12,7 +12,11 @@ dotenv.config();
|
||||
const run = async () => {
|
||||
const logger = await initLogger();
|
||||
const appCfg = initEnvConfig(logger);
|
||||
const db = initDbConnection(appCfg.DB_CONNECTION_URI);
|
||||
const db = initDbConnection({
|
||||
dbConnectionUri: appCfg.DB_CONNECTION_URI,
|
||||
dbRootCert: appCfg.DB_ROOT_CERT
|
||||
});
|
||||
|
||||
const smtp = smtpServiceFactory(formatSmtpConfig());
|
||||
const queue = queueServiceFactory(appCfg.REDIS_URL);
|
||||
|
||||
@@ -36,7 +40,7 @@ const run = async () => {
|
||||
port: appCfg.PORT,
|
||||
host: appCfg.HOST,
|
||||
listenTextResolver: (address) => {
|
||||
bootstrap();
|
||||
void bootstrap();
|
||||
return address;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,11 +14,10 @@ import fasitfy from "fastify";
|
||||
import { Knex } from "knex";
|
||||
import { Logger } from "pino";
|
||||
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { TQueueServiceFactory } from "@app/queue";
|
||||
import { TSmtpService } from "@app/services/smtp/smtp-service";
|
||||
|
||||
import { getConfig } from "@lib/config/env";
|
||||
|
||||
import { globalRateLimiterCfg } from "./config/rateLimiter";
|
||||
import { fastifyErrHandler } from "./plugins/error-handler";
|
||||
import { registerExternalNextjs } from "./plugins/external-nextjs";
|
||||
@@ -40,6 +39,7 @@ export const main = async ({ db, smtp, logger, queue }: TMain) => {
|
||||
const server = fasitfy({
|
||||
logger,
|
||||
trustProxy: true,
|
||||
connectionTimeout: 30 * 1000,
|
||||
ignoreTrailingSlash: true
|
||||
}).withTypeProvider<ZodTypeProvider>();
|
||||
|
||||
@@ -75,7 +75,7 @@ export const main = async ({ db, smtp, logger, queue }: TMain) => {
|
||||
if (appCfg.isProductionMode) {
|
||||
await server.register(registerExternalNextjs, {
|
||||
standaloneMode: appCfg.STANDALONE_MODE,
|
||||
dir: path.join(__dirname, "../"),
|
||||
dir: path.join(__dirname, "../../"),
|
||||
port: appCfg.PORT
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ type BootstrapOpt = {
|
||||
db: Knex;
|
||||
};
|
||||
|
||||
const bootstrapCb = () => {
|
||||
const bootstrapCb = async () => {
|
||||
const appCfg = getConfig();
|
||||
const serverCfg = getServerCfg();
|
||||
const serverCfg = await getServerCfg();
|
||||
if (!serverCfg.initialized) {
|
||||
console.info(`Welcome to Infisical
|
||||
|
||||
|
||||
@@ -45,6 +45,9 @@ export const registerExternalNextjs = async (
|
||||
server.route({
|
||||
method: ["GET", "PUT", "PATCH", "POST", "DELETE"],
|
||||
url: "/*",
|
||||
schema: {
|
||||
hide: true
|
||||
},
|
||||
handler: (req, res) =>
|
||||
nextApp
|
||||
.getRequestHandler()(req.raw, res.raw)
|
||||
|
||||
@@ -43,6 +43,7 @@ export const fastifySwagger = fp(async (fastify) => {
|
||||
});
|
||||
|
||||
await fastify.register(swaggerUI, {
|
||||
routePrefix: "/docs"
|
||||
routePrefix: "/api/docs",
|
||||
prefix: "/api/docs"
|
||||
});
|
||||
});
|
||||
|
||||
@@ -513,9 +513,9 @@ export const registerRoutes = async (
|
||||
})
|
||||
}
|
||||
},
|
||||
handler: () => {
|
||||
handler: async () => {
|
||||
const cfg = getConfig();
|
||||
const serverCfg = getServerCfg();
|
||||
const serverCfg = await getServerCfg();
|
||||
return {
|
||||
date: new Date(),
|
||||
message: "Ok" as const,
|
||||
|
||||
@@ -20,8 +20,8 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
})
|
||||
}
|
||||
},
|
||||
handler: () => {
|
||||
const config = getServerCfg();
|
||||
handler: async () => {
|
||||
const config = await getServerCfg();
|
||||
return { config };
|
||||
}
|
||||
});
|
||||
@@ -78,7 +78,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
},
|
||||
handler: async (req, res) => {
|
||||
const appCfg = getConfig();
|
||||
const serverCfg = getServerCfg();
|
||||
const serverCfg = await getServerCfg();
|
||||
if (serverCfg.initialized)
|
||||
throw new UnauthorizedError({ name: "Admin sign up", message: "Admin has been created" });
|
||||
const { user, token } = await server.services.superAdmin.adminSignUp({
|
||||
|
||||
@@ -42,7 +42,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
||||
async (req, _accessToken, _refreshToken, profile, cb) => {
|
||||
try {
|
||||
const email = profile?.emails?.[0]?.value;
|
||||
const serverCfg = getServerCfg();
|
||||
const serverCfg = await getServerCfg();
|
||||
if (!email)
|
||||
throw new BadRequestError({
|
||||
message: "Email not found",
|
||||
@@ -84,7 +84,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
||||
try {
|
||||
const ghEmails = await fetchGithubEmails(accessToken);
|
||||
const { email } = ghEmails.filter((gitHubEmail) => gitHubEmail.primary)[0];
|
||||
const serverCfg = getServerCfg();
|
||||
const serverCfg = await getServerCfg();
|
||||
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
||||
email,
|
||||
firstName: profile.displayName,
|
||||
@@ -120,7 +120,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
||||
async (req: any, _accessToken: string, _refreshToken: string, profile: any, cb: any) => {
|
||||
try {
|
||||
const email = profile.emails[0].value;
|
||||
const serverCfg = getServerCfg();
|
||||
const serverCfg = await getServerCfg();
|
||||
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
||||
email,
|
||||
firstName: profile.displayName,
|
||||
|
||||
@@ -478,7 +478,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
|
||||
// TODO: Move to telemetry plugin
|
||||
let shouldRecordK8Event = false;
|
||||
if (req.headers["user-agent"] === "k8-operator") {
|
||||
if (req.headers["user-agent"] === "k8-operatoer") {
|
||||
const randomNumber = Math.random();
|
||||
if (randomNumber > 0.95) {
|
||||
shouldRecordK8Event = true;
|
||||
|
||||
@@ -21,7 +21,11 @@ export const projectDALFactory = (db: TDbClient) => {
|
||||
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
||||
db.ref("name").withSchema(TableName.Environment).as("envName")
|
||||
)
|
||||
.orderBy("createdAt", "asc", "last");
|
||||
.orderBy([
|
||||
{ column: `${TableName.Project}.name`, order: "asc" },
|
||||
{ column: `${TableName.Environment}.position`, order: "asc" }
|
||||
]);
|
||||
|
||||
const nestedWorkspaces = sqlNestRelationships({
|
||||
data: workspaces,
|
||||
key: "id",
|
||||
@@ -102,7 +106,11 @@ export const projectDALFactory = (db: TDbClient) => {
|
||||
db.ref("id").withSchema(TableName.Environment).as("envId"),
|
||||
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
||||
db.ref("name").withSchema(TableName.Environment).as("envName")
|
||||
);
|
||||
)
|
||||
.orderBy([
|
||||
{ column: `${TableName.Project}.name`, order: "asc" },
|
||||
{ column: `${TableName.Environment}.position`, order: "asc" }
|
||||
]);
|
||||
return sqlNestRelationships({
|
||||
data: workspaces,
|
||||
key: "id",
|
||||
|
||||
@@ -569,18 +569,30 @@ export const secretServiceFactory = ({
|
||||
|
||||
const secretBlindIndex = await interalGenSecBlindIndexByName(projectId, secretName);
|
||||
|
||||
const secret = await (typeof version !== undefined
|
||||
// Case: The old python SDK uses incorrect logic https://github.com/Infisical/infisical-python/blob/main/infisical/client/infisicalclient.py#L89.
|
||||
// Fetch secrets using service tokens cannot fetch personal secrets, only shared.
|
||||
// The mongo backend used to correct this mistake, this line also adds it to current backend
|
||||
// Mongo backend check: https://github.com/Infisical/infisical-mongo/blob/main/backend/src/helpers/secrets.ts#L658
|
||||
let secretType = type;
|
||||
if (actor === ActorType.SERVICE) {
|
||||
logger.info(
|
||||
`secretServiceFactory: overriding secret type for service token [projectId=${projectId}] [factoryFunctionName=getSecretByName]`
|
||||
);
|
||||
secretType = SecretType.Shared;
|
||||
}
|
||||
|
||||
const secret = await (typeof version === undefined
|
||||
? secretDAL.findOne({
|
||||
folderId,
|
||||
type,
|
||||
userId: type === SecretType.Personal ? actorId : null,
|
||||
type: secretType,
|
||||
userId: secretType === SecretType.Personal ? actorId : null,
|
||||
secretBlindIndex
|
||||
})
|
||||
: secretVersionDAL
|
||||
.findOne({
|
||||
folderId,
|
||||
type,
|
||||
userId: type === SecretType.Personal ? actorId : null,
|
||||
type: secretType,
|
||||
userId: secretType === SecretType.Personal ? actorId : null,
|
||||
secretBlindIndex
|
||||
})
|
||||
.then((el) => SecretsSchema.parse({ ...el, id: el.secretId })));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { TSuperAdmin, TSuperAdminUpdate } from "@app/db/schemas";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
|
||||
import { TAuthLoginFactory } from "../auth/auth-login-service";
|
||||
@@ -17,11 +18,8 @@ type TSuperAdminServiceFactoryDep = {
|
||||
|
||||
export type TSuperAdminServiceFactory = ReturnType<typeof superAdminServiceFactory>;
|
||||
|
||||
let serverCfg: Readonly<TSuperAdmin>;
|
||||
export const getServerCfg = () => {
|
||||
if (!serverCfg) throw new BadRequestError({ name: "Get server cfg", message: "Server cfg not initialized" });
|
||||
return serverCfg;
|
||||
};
|
||||
// eslint-disable-next-line
|
||||
export let getServerCfg: () => Promise<TSuperAdmin>;
|
||||
|
||||
export const superAdminServiceFactory = ({
|
||||
serverCfgDAL,
|
||||
@@ -30,19 +28,18 @@ export const superAdminServiceFactory = ({
|
||||
orgService
|
||||
}: TSuperAdminServiceFactoryDep) => {
|
||||
const initServerCfg = async () => {
|
||||
serverCfg = await serverCfgDAL.findOne({});
|
||||
if (!serverCfg) {
|
||||
const newCfg = await serverCfgDAL.create({ initialized: false, allowSignUp: true });
|
||||
serverCfg = newCfg;
|
||||
return newCfg;
|
||||
}
|
||||
return serverCfg;
|
||||
// TODO(akhilmhdh): bad pattern time less change this later to me itself
|
||||
getServerCfg = () => serverCfgDAL.findOne({});
|
||||
|
||||
const serverCfg = await serverCfgDAL.findOne({});
|
||||
if (serverCfg) return;
|
||||
const newCfg = await serverCfgDAL.create({ initialized: false, allowSignUp: true });
|
||||
return newCfg;
|
||||
};
|
||||
|
||||
const updateServerCfg = async (data: TSuperAdminUpdate) => {
|
||||
const serverCfg = await getServerCfg();
|
||||
const cfg = await serverCfgDAL.updateById(serverCfg.id, data);
|
||||
serverCfg = cfg;
|
||||
Object.freeze(serverCfg);
|
||||
return cfg;
|
||||
};
|
||||
|
||||
@@ -62,6 +59,7 @@ export const superAdminServiceFactory = ({
|
||||
ip,
|
||||
userAgent
|
||||
}: TAdminSignUpDTO) => {
|
||||
const appCfg = getConfig();
|
||||
const existingUser = await userDAL.findOne({ email });
|
||||
if (existingUser) throw new BadRequestError({ name: "Admin sign up", message: "User already exist" });
|
||||
|
||||
@@ -95,7 +93,10 @@ export const superAdminServiceFactory = ({
|
||||
);
|
||||
return { user: newUser, enc: userEnc };
|
||||
});
|
||||
await orgService.createOrganization(userInfo.user.id, userInfo.user.email, "Admin Org");
|
||||
|
||||
const initialOrganizationName = appCfg.INITIAL_ORGANIZATION_NAME ?? "Admin Org";
|
||||
|
||||
await orgService.createOrganization(userInfo.user.id, userInfo.user.email, initialOrganizationName);
|
||||
|
||||
await updateServerCfg({ initialized: true });
|
||||
const token = await authService.generateUserTokens({
|
||||
|
||||
Reference in New Issue
Block a user