Compare commits

...

9 Commits

Author SHA1 Message Date
cee982754b Requested changes 2024-09-18 20:41:21 +04:00
a6497b844a remove unneeded comments 2024-09-18 09:22:58 -04:00
788dcf2c73 Update warning message 2024-09-18 09:21:11 -04:00
7f055450df Update root.go 2024-09-18 12:55:03 +04:00
9234213c62 Requested changes 2024-09-18 12:50:28 +04:00
e7278c4cd9 Requested changes 2024-09-18 01:35:01 +04:00
3e79dbb3f5 feat(cli): warning when logged in and using token at the same time 2024-09-18 01:34:01 +04:00
9b2565e387 Update error-handler.ts 2024-09-17 22:57:43 +04:00
1c5a8cabe9 feat: better api errors 2024-09-17 22:53:51 +04:00
9 changed files with 124 additions and 24 deletions

View File

@ -1,5 +1,6 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import fastifyPlugin from "fastify-plugin"; import fastifyPlugin from "fastify-plugin";
import { JsonWebTokenError } from "jsonwebtoken";
import { ZodError } from "zod"; import { ZodError } from "zod";
import { import {
@ -11,6 +12,12 @@ import {
UnauthorizedError UnauthorizedError
} from "@app/lib/errors"; } from "@app/lib/errors";
enum JWTErrors {
JwtExpired = "jwt expired",
JwtMalformed = "jwt malformed",
InvalidAlgorithm = "invalid algorithm"
}
export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider) => { export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider) => {
server.setErrorHandler((error, req, res) => { server.setErrorHandler((error, req, res) => {
req.log.error(error); req.log.error(error);
@ -36,6 +43,27 @@ export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider
status: error.status, status: error.status,
detail: error.detail detail: error.detail
}); });
// Handle JWT errors and make them more human-readable for the end-user.
} else if (error instanceof JsonWebTokenError) {
const message = (() => {
if (error.message === JWTErrors.JwtExpired) {
return "Your token has expired. Please re-authenticate.";
}
if (error.message === JWTErrors.JwtMalformed) {
return "The provided access token is malformed. Please use a valid token or generate a new one and try again.";
}
if (error.message === JWTErrors.InvalidAlgorithm) {
return "The access token is signed with an invalid algorithm. Please provide a valid token and try again.";
}
return error.message;
})();
void res.status(401).send({
statusCode: 401,
error: "TokenError",
message
});
} else { } else {
void res.send(error); void res.send(error);
} }

View File

@ -26,7 +26,10 @@ export const getBotKeyFnFactory = (
) => { ) => {
const getBotKeyFn = async (projectId: string) => { const getBotKeyFn = async (projectId: string) => {
const project = await projectDAL.findById(projectId); const project = await projectDAL.findById(projectId);
if (!project) throw new BadRequestError({ message: "Project not found during bot lookup." }); if (!project)
throw new BadRequestError({
message: "Project not found during bot lookup. Are you sure you are using the correct project ID?"
});
if (project.version === 3) { if (project.version === 3) {
return { project, shouldUseSecretV2Bridge: true }; return { project, shouldUseSecretV2Bridge: true };

View File

@ -512,7 +512,11 @@ export const secretImportServiceFactory = ({
return importedSecrets; return importedSecrets;
} }
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); if (!botKey)
throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
const importedSecrets = await fnSecretsFromImports({ allowedImports, folderDAL, secretDAL, secretImportDAL }); const importedSecrets = await fnSecretsFromImports({ allowedImports, folderDAL, secretDAL, secretImportDAL });
return importedSecrets.map((el) => ({ return importedSecrets.map((el) => ({

View File

@ -832,7 +832,11 @@ export const createManySecretsRawFnFactory = ({
secretDAL secretDAL
}); });
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); if (!botKey)
throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
const inputSecrets = secrets.map((secret) => { const inputSecrets = secrets.map((secret) => {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secret.secretName, botKey); const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secret.secretName, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secret.secretValue || "", botKey); const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secret.secretValue || "", botKey);
@ -993,7 +997,11 @@ export const updateManySecretsRawFnFactory = ({
return updatedSecrets; return updatedSecrets;
} }
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); if (!botKey)
throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId }); const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "Update secret" }); if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "Update secret" });

View File

@ -985,7 +985,11 @@ export const secretServiceFactory = ({
return { secrets, imports }; return { secrets, imports };
} }
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); if (!botKey)
throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
const { secrets, imports } = await getSecrets({ const { secrets, imports } = await getSecrets({
actorId, actorId,
@ -1146,7 +1150,10 @@ export const secretServiceFactory = ({
}); });
if (!botKey) if (!botKey)
throw new BadRequestError({ message: "Please upgrade your project first", name: "bot_not_found_error" }); throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
const decryptedSecret = decryptSecretRaw(encryptedSecret, botKey); const decryptedSecret = decryptSecretRaw(encryptedSecret, botKey);
if (expandSecretReferences) { if (expandSecretReferences) {
@ -1238,7 +1245,11 @@ export const secretServiceFactory = ({
return { secret, type: SecretProtectionType.Direct as const }; return { secret, type: SecretProtectionType.Direct as const };
} }
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); if (!botKey)
throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretName, botKey); const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretName, botKey);
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey); const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey); const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
@ -1376,7 +1387,11 @@ export const secretServiceFactory = ({
return { type: SecretProtectionType.Direct as const, secret }; return { type: SecretProtectionType.Direct as const, secret };
} }
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); if (!botKey)
throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey); const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey); const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
@ -1498,7 +1513,11 @@ export const secretServiceFactory = ({
}); });
return { type: SecretProtectionType.Direct as const, secret }; return { type: SecretProtectionType.Direct as const, secret };
} }
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); if (!botKey)
throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
if (policy) { if (policy) {
const approval = await secretApprovalRequestService.generateSecretApprovalRequest({ const approval = await secretApprovalRequestService.generateSecretApprovalRequest({
policy, policy,
@ -1598,7 +1617,11 @@ export const secretServiceFactory = ({
return { secrets, type: SecretProtectionType.Direct as const }; return { secrets, type: SecretProtectionType.Direct as const };
} }
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); if (!botKey)
throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
const sanitizedSecrets = inputSecrets.map( const sanitizedSecrets = inputSecrets.map(
({ secretComment, secretKey, metadata, tagIds, secretValue, skipMultilineEncoding }) => { ({ secretComment, secretKey, metadata, tagIds, secretValue, skipMultilineEncoding }) => {
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretKey, botKey); const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretKey, botKey);
@ -1720,7 +1743,11 @@ export const secretServiceFactory = ({
return { type: SecretProtectionType.Direct as const, secrets }; return { type: SecretProtectionType.Direct as const, secrets };
} }
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); if (!botKey)
throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
const sanitizedSecrets = inputSecrets.map( const sanitizedSecrets = inputSecrets.map(
({ ({
secretComment, secretComment,
@ -1848,7 +1875,11 @@ export const secretServiceFactory = ({
return { type: SecretProtectionType.Direct as const, secrets }; return { type: SecretProtectionType.Direct as const, secrets };
} }
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); if (!botKey)
throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
if (policy) { if (policy) {
const approval = await secretApprovalRequestService.generateSecretApprovalRequest({ const approval = await secretApprovalRequestService.generateSecretApprovalRequest({
@ -2182,7 +2213,10 @@ export const secretServiceFactory = ({
} }
if (!botKey) if (!botKey)
throw new BadRequestError({ message: "Please upgrade your project first", name: "bot_not_found_error" }); throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
await secretDAL.transaction(async (tx) => { await secretDAL.transaction(async (tx) => {
const secrets = await secretDAL.findAllProjectSecretValues(projectId, tx); const secrets = await secretDAL.findAllProjectSecretValues(projectId, tx);
@ -2265,7 +2299,10 @@ export const secretServiceFactory = ({
const { botKey } = await projectBotService.getBotKey(project.id); const { botKey } = await projectBotService.getBotKey(project.id);
if (!botKey) { if (!botKey) {
throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" }); throw new BadRequestError({
message: "Project bot not found. Please upgrade your project.",
name: "bot_not_found_error"
});
} }
const sourceFolder = await folderDAL.findBySecretPath(project.id, sourceEnvironment, sourceSecretPath); const sourceFolder = await folderDAL.findBySecretPath(project.id, sourceEnvironment, sourceSecretPath);

View File

@ -4,6 +4,7 @@ Copyright (c) 2023 Infisical Inc.
package cmd package cmd
import ( import (
"fmt"
"os" "os"
"strings" "strings"
@ -43,14 +44,26 @@ func init() {
rootCmd.PersistentFlags().Bool("silent", false, "Disable output of tip/info messages. Useful when running in scripts or CI/CD pipelines.") rootCmd.PersistentFlags().Bool("silent", false, "Disable output of tip/info messages. Useful when running in scripts or CI/CD pipelines.")
rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
silent, err := cmd.Flags().GetBool("silent") silent, err := cmd.Flags().GetBool("silent")
config.INFISICAL_URL = util.AppendAPIEndpoint(config.INFISICAL_URL)
if err != nil { if err != nil {
util.HandleError(err) util.HandleError(err)
} }
config.INFISICAL_URL = util.AppendAPIEndpoint(config.INFISICAL_URL)
if !util.IsRunningInDocker() && !silent { if !util.IsRunningInDocker() && !silent {
util.CheckForUpdate() util.CheckForUpdate()
} }
loggedInDetails, err := util.GetCurrentLoggedInUserDetails()
if !silent && err == nil && loggedInDetails.IsUserLoggedIn && !loggedInDetails.LoginExpired {
token, err := util.GetInfisicalToken(cmd)
if err == nil && token != nil {
util.PrintWarning(fmt.Sprintf("Your logged-in session is being overwritten by the token provided from the %s.", token.Source))
}
}
} }
// if config.INFISICAL_URL is set to the default value, check if INFISICAL_URL is set in the environment // if config.INFISICAL_URL is set to the default value, check if INFISICAL_URL is set in the environment

View File

@ -160,19 +160,19 @@ var secretsSetCmd = &cobra.Command{
util.HandleError(err, "Unable to parse flag") util.HandleError(err, "Unable to parse flag")
} }
if (token == nil) { if token == nil {
util.RequireLocalWorkspaceFile() util.RequireLocalWorkspaceFile()
} }
environmentName, _ := cmd.Flags().GetString("env") environmentName, _ := cmd.Flags().GetString("env")
if !cmd.Flags().Changed("env") { if !cmd.Flags().Changed("env") {
environmentFromWorkspace := util.GetEnvFromWorkspaceFile() environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
if environmentFromWorkspace != "" { if environmentFromWorkspace != "" {
environmentName = environmentFromWorkspace environmentName = environmentFromWorkspace
} }
} }
projectId, err := cmd.Flags().GetString("projectId") projectId, err := cmd.Flags().GetString("projectId")
if err != nil { if err != nil {
util.HandleError(err, "Unable to parse flag") util.HandleError(err, "Unable to parse flag")
} }

View File

@ -63,8 +63,9 @@ type DynamicSecretLease struct {
} }
type TokenDetails struct { type TokenDetails struct {
Type string Type string
Token string Token string
Source string
} }
type SingleFolder struct { type SingleFolder struct {

View File

@ -87,11 +87,15 @@ func GetInfisicalToken(cmd *cobra.Command) (token *models.TokenDetails, err erro
return nil, err return nil, err
} }
var source = "--token flag"
if infisicalToken == "" { // If no flag is passed, we first check for the universal auth access token env variable. if infisicalToken == "" { // If no flag is passed, we first check for the universal auth access token env variable.
infisicalToken = os.Getenv(INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN_NAME) infisicalToken = os.Getenv(INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN_NAME)
source = fmt.Sprintf("%s environment variable", INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN_NAME)
if infisicalToken == "" { // If it's still empty after the first env check, we check for the service token env variable. if infisicalToken == "" { // If it's still empty after the first env check, we check for the service token env variable.
infisicalToken = os.Getenv(INFISICAL_TOKEN_NAME) infisicalToken = os.Getenv(INFISICAL_TOKEN_NAME)
source = fmt.Sprintf("%s environment variable", INFISICAL_TOKEN_NAME)
} }
} }
@ -101,14 +105,16 @@ func GetInfisicalToken(cmd *cobra.Command) (token *models.TokenDetails, err erro
if strings.HasPrefix(infisicalToken, "st.") { if strings.HasPrefix(infisicalToken, "st.") {
return &models.TokenDetails{ return &models.TokenDetails{
Type: SERVICE_TOKEN_IDENTIFIER, Type: SERVICE_TOKEN_IDENTIFIER,
Token: infisicalToken, Token: infisicalToken,
Source: source,
}, nil }, nil
} }
return &models.TokenDetails{ return &models.TokenDetails{
Type: UNIVERSAL_AUTH_TOKEN_IDENTIFIER, Type: UNIVERSAL_AUTH_TOKEN_IDENTIFIER,
Token: infisicalToken, Token: infisicalToken,
Source: source,
}, nil }, nil
} }