Compare commits

..

4 Commits

Author SHA1 Message Date
x032205
2a9e31d305 Few nits 2025-07-03 13:11:53 -04:00
x032205
fb2f1731dd Merge branch 'main' into password-reset-ui 2025-07-03 13:02:48 -04:00
Scott Wilson
69157cb912 improvement: add period 2025-07-01 19:23:13 -07:00
Scott Wilson
44eb761d5b improvement: re-vamp password reset flow pages/steps to match login design 2025-07-01 19:19:27 -07:00
10 changed files with 158 additions and 136 deletions

View File

@@ -35,7 +35,6 @@ const (
GitHubPlatform
GitLabPlatform
AzureDevOpsPlatform
BitBucketPlatform
// TODO: Add others.
)
@@ -46,7 +45,6 @@ func (p Platform) String() string {
"github",
"gitlab",
"azuredevops",
"bitbucket",
}[p]
}
@@ -62,8 +60,6 @@ func PlatformFromString(s string) (Platform, error) {
return GitLabPlatform, nil
case "azuredevops":
return AzureDevOpsPlatform, nil
case "bitbucket":
return BitBucketPlatform, nil
default:
return UnknownPlatform, fmt.Errorf("invalid scm platform value: %s", s)
}

View File

@@ -208,8 +208,6 @@ func platformFromHost(u *url.URL) scm.Platform {
return scm.GitLabPlatform
case "dev.azure.com", "visualstudio.com":
return scm.AzureDevOpsPlatform
case "bitbucket.org":
return scm.BitBucketPlatform
default:
return scm.UnknownPlatform
}

View File

@@ -112,15 +112,6 @@ func createScmLink(scmPlatform scm.Platform, remoteUrl string, finding report.Fi
// This is a bit dirty, but Azure DevOps does not highlight the line when the lineStartColumn and lineEndColumn are not provided
link += "&lineStartColumn=1&lineEndColumn=10000000&type=2&lineStyle=plain&_a=files"
return link
case scm.BitBucketPlatform:
link := fmt.Sprintf("%s/src/%s/%s", remoteUrl, finding.Commit, filePath)
if finding.StartLine != 0 {
link += fmt.Sprintf("#lines-%d", finding.StartLine)
}
if finding.EndLine != finding.StartLine {
link += fmt.Sprintf(":%d", finding.EndLine)
}
return link
default:
// This should never happen.
return ""

View File

@@ -337,7 +337,9 @@ var scanCmd = &cobra.Command{
if gitCmd, err = sources.NewGitLogCmd(source, logOpts); err != nil {
logging.Fatal().Err(err).Msg("could not create Git cmd")
}
scmPlatform = scm.UnknownPlatform
if scmPlatform, err = scm.PlatformFromString("github"); err != nil {
logging.Fatal().Err(err).Send()
}
remote = detect.NewRemoteInfo(scmPlatform, source)
if findings, err = detector.DetectGit(gitCmd, remote); err != nil {

View File

@@ -1,19 +1,33 @@
import { Helmet } from "react-helmet";
import { Link } from "@tanstack/react-router";
export const EmailNotVerifiedPage = () => {
return (
<div className="flex flex-col justify-between bg-bunker-800 md:h-screen">
<div className="flex min-h-screen flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28">
<Helmet>
<title>Request a New Invite</title>
<link rel="icon" href="/infisical.ico" />
</Helmet>
<div className="flex h-screen w-screen flex-col items-center justify-center text-gray-200">
<p className="text-6xl">Oops.</p>
<p className="mb-1 mt-2 text-xl">Your email was not verified. </p>
<p className="text-xl">Please try again.</p>
<p className="text-md mt-8 max-w-sm text-center text-gray-600">
Note: If it still doesn&apos;t work, please reach out to us at support@infisical.com
<Link to="/">
<div className="mb-4 mt-20 flex justify-center">
<img src="/images/gradientLogo.svg" className="h-[90px] w-[120px]" alt="Infisical Logo" />
</div>
</Link>
<div className="mx-auto flex w-full flex-col items-center justify-center">
<h1 className="mb-2 bg-gradient-to-b from-white to-bunker-200 bg-clip-text text-center text-xl font-medium text-transparent">
Your email was not verified
</h1>
<p className="w-max justify-center text-center text-sm text-gray-400">
Please try again. <br /> Note: If it still doesn&apos;t work, please reach out to us at
support@infisical.com
</p>
<div className="mt-6 flex flex-row text-sm text-bunker-400">
<Link to="/login">
<span className="cursor-pointer duration-200 hover:text-bunker-200 hover:underline hover:decoration-primary-700 hover:underline-offset-4">
Back to Login
</span>
</Link>
</div>
</div>
</div>
);

View File

@@ -1,7 +1,7 @@
import { useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useNavigate } from "@tanstack/react-router";
import { Link, useNavigate } from "@tanstack/react-router";
import { z } from "zod";
import { UserEncryptionVersion } from "@app/hooks/api/auth/types";
@@ -36,7 +36,12 @@ export const PasswordResetPage = () => {
const navigate = useNavigate();
return (
<div className="flex h-screen w-full flex-col items-center justify-center bg-bunker-800">
<div className="flex min-h-screen flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28">
<Link to="/">
<div className="mb-4 mt-20 flex justify-center">
<img src="/images/gradientLogo.svg" className="h-[90px] w-[120px]" alt="Infisical Logo" />
</div>
</Link>
{step === Steps.ConfirmEmail && (
<ConfirmEmailStep
onComplete={(verifyToken, userEncryptionVersion) => {

View File

@@ -19,17 +19,21 @@ export const ConfirmEmailStep = ({ onComplete }: Props) => {
isPending: isVerifyPasswordResetLoading
} = useVerifyPasswordResetCode();
return (
<div className="mx-1 my-32 flex w-full max-w-xs flex-col items-center rounded-xl bg-bunker px-4 py-6 drop-shadow-xl md:max-w-lg md:px-6">
<p className="mb-8 flex justify-center bg-gradient-to-br from-sky-400 to-primary bg-clip-text text-center text-4xl font-semibold text-transparent">
<div className="mx-auto flex w-full flex-col items-center justify-center">
<h1 className="mb-2 bg-gradient-to-b from-white to-bunker-200 bg-clip-text text-center text-xl font-medium text-transparent">
Confirm your email
</h1>
<p className="mb-8 w-max justify-center text-center text-sm text-gray-400">
Reset password for <span className="italic">{email}</span>.
</p>
<img
src="/images/envelope.svg"
style={{ height: "262px", width: "410px" }}
alt="verify email"
/>
<div className="mx-auto mb-2 mt-4 flex max-h-24 max-w-md flex-col items-center justify-center px-4 text-lg md:p-2">
<div className="w-1/4 min-w-[21.2rem] rounded-md text-center md:min-w-[20.1rem] lg:w-1/6">
<Button
type="submit"
size="sm"
isFullWidth
className="h-10"
colorSchema="primary"
variant="solid"
onClick={async () => {
try {
const response = await verifyPasswordResetCodeMutateAsync({
@@ -44,7 +48,6 @@ export const ConfirmEmailStep = ({ onComplete }: Props) => {
}
}}
isLoading={isVerifyPasswordResetLoading}
size="lg"
>
Confirm Email
</Button>

View File

@@ -1,7 +1,7 @@
import crypto from "crypto";
import { Controller, useForm } from "react-hook-form";
import { faCheck, faX } from "@fortawesome/free-solid-svg-icons";
import { faCheck, faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import { useSearch } from "@tanstack/react-router";
@@ -169,17 +169,15 @@ export const EnterPasswordStep = ({
return (
<form
onSubmit={handleSubmit(resetPasswordHandler)}
className="mx-1 my-32 flex w-full max-w-xs flex-col items-center rounded-xl bg-bunker px-4 pb-3 pt-6 drop-shadow-xl md:max-w-lg md:px-6"
className="mx-auto flex w-full flex-col items-center justify-center"
>
<p className="mx-auto flex w-max justify-center text-2xl font-semibold text-bunker-100 md:text-3xl">
<h1 className="mb-2 bg-gradient-to-b from-white to-bunker-200 bg-clip-text text-center text-xl font-medium text-transparent">
Enter new password
</h1>
<p className="w-max justify-center text-center text-sm text-gray-400">
Make sure you save it somewhere safe.
</p>
<div className="mt-1 flex flex-row items-center justify-center md:mx-2 md:pb-4">
<p className="flex w-max max-w-md justify-center text-sm text-gray-400">
Make sure you save it somewhere safe.
</p>
</div>
<div className="mt-4 flex max-h-24 w-full items-center justify-center rounded-lg md:mt-0 md:max-h-28 md:p-2">
<div className="mt-8 w-1/4 min-w-[21.2rem] rounded-md text-center md:min-w-[20.1rem] lg:w-1/6">
<Controller
control={control}
name="password"
@@ -202,6 +200,20 @@ export const EnterPasswordStep = ({
)}
/>
</div>
<div className="w-1/4 min-w-[21.2rem] rounded-md text-center md:min-w-[20.1rem] lg:w-1/6">
<Button
type="submit"
size="sm"
isFullWidth
className="h-10"
colorSchema="primary"
variant="solid"
isLoading={isSubmitting || isLoading || isLoadingV2}
isDisabled={isSubmitting || isLoading || isLoadingV2}
>
Change Password
</Button>
</div>
{passwordErrorTooShort ||
passwordErrorTooLong ||
passwordErrorNoLetterChar ||
@@ -210,33 +222,33 @@ export const EnterPasswordStep = ({
passwordErrorEscapeChar ||
passwordErrorLowEntropy ||
passwordErrorBreached ? (
<div className="mx-2 mb-2 mt-3 flex w-full max-w-md flex-col items-start rounded-md bg-white/5 px-2 py-2">
<div className="mb-1 text-sm text-gray-400">Password should contain:</div>
<div className="ml-1 flex flex-row items-center justify-start">
<div className="mt-4 rounded border border-mineshaft-600 bg-mineshaft-800 p-4 drop-shadow">
<div className="mb-1 ml-2 text-sm text-gray-300">Password should contain:</div>
<div className="ml-2 flex flex-row items-center justify-start">
{passwordErrorTooShort ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
<FontAwesomeIcon icon={faXmark} className="mr-2.5 text-lg text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-green" />
)}
<div className={`${passwordErrorTooShort ? "text-gray-400" : "text-gray-600"} text-sm`}>
at least 14 characters
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
<div className="ml-2 flex flex-row items-center justify-start">
{passwordErrorTooLong ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
<FontAwesomeIcon icon={faXmark} className="mr-2.5 text-lg text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-green" />
)}
<div className={`${passwordErrorTooLong ? "text-gray-400" : "text-gray-600"} text-sm`}>
at most 100 characters
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
<div className="ml-2 flex flex-row items-center justify-start">
{passwordErrorNoLetterChar ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
<FontAwesomeIcon icon={faXmark} className="mr-2.5 text-lg text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-green" />
)}
<div
className={`${passwordErrorNoLetterChar ? "text-gray-400" : "text-gray-600"} text-sm`}
@@ -244,11 +256,11 @@ export const EnterPasswordStep = ({
at least 1 letter character
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
<div className="ml-2 flex flex-row items-center justify-start">
{passwordErrorNoNumOrSpecialChar ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
<FontAwesomeIcon icon={faXmark} className="mr-2.5 text-lg text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-green" />
)}
<div
className={`${
@@ -258,11 +270,11 @@ export const EnterPasswordStep = ({
at least 1 number or special character
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
<div className="ml-2 flex flex-row items-center justify-start">
{passwordErrorRepeatedChar ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
<FontAwesomeIcon icon={faXmark} className="mr-2.5 text-lg text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-green" />
)}
<div
className={`${passwordErrorRepeatedChar ? "text-gray-400" : "text-gray-600"} text-sm`}
@@ -270,11 +282,11 @@ export const EnterPasswordStep = ({
at most 3 repeated, consecutive characters
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
<div className="ml-2 flex flex-row items-center justify-start">
{passwordErrorEscapeChar ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
<FontAwesomeIcon icon={faXmark} className="mr-2.5 text-lg text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-green" />
)}
<div
className={`${passwordErrorEscapeChar ? "text-gray-400" : "text-gray-600"} text-sm`}
@@ -282,11 +294,11 @@ export const EnterPasswordStep = ({
No escape characters allowed.
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
<div className="ml-2 flex flex-row items-center justify-start">
{passwordErrorLowEntropy ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
<FontAwesomeIcon icon={faXmark} className="mr-2.5 text-lg text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-green" />
)}
<div
className={`${passwordErrorLowEntropy ? "text-gray-400" : "text-gray-600"} text-sm`}
@@ -294,32 +306,18 @@ export const EnterPasswordStep = ({
Password contains personal info.
</div>
</div>
<div className="ml-1 flex flex-row items-center justify-start">
<div className="ml-2 flex flex-row items-center justify-start">
{passwordErrorBreached ? (
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
<FontAwesomeIcon icon={faXmark} className="mr-2.5 text-lg text-red" />
) : (
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-green" />
)}
<div className={`${passwordErrorBreached ? "text-gray-400" : "text-gray-600"} text-sm`}>
Password was found in a data breach.
</div>
</div>
</div>
) : (
<div className="py-2" />
)}
<div className="mx-auto mt-4 flex max-h-20 w-full max-w-md flex-col items-center justify-center text-sm md:p-2">
<div className="text-l m-8 mt-6 px-8 py-3 text-lg">
<Button
type="submit"
colorSchema="secondary"
isLoading={isSubmitting || isLoading || isLoadingV2}
isDisabled={isSubmitting || isLoading || isLoadingV2}
>
Change Password
</Button>
</div>
</div>
) : null}
</form>
);
};

View File

@@ -43,18 +43,15 @@ export const InputBackupKeyStep = ({ verificationToken, onComplete }: Props) =>
return (
<form
onSubmit={handleSubmit(getEncryptedKeyHandler)}
className="mx-1 my-32 flex w-full max-w-xs flex-col items-center rounded-xl bg-bunker px-4 pb-3 pt-6 drop-shadow-xl md:max-w-lg md:px-6"
className="mx-auto flex w-full flex-col items-center justify-center"
>
<p className="mx-auto mb-4 flex w-max justify-center text-2xl font-semibold text-bunker-100">
<h1 className="mb-2 bg-gradient-to-b from-white to-bunker-200 bg-clip-text text-center text-xl font-medium text-transparent">
Enter your backup key
</h1>
<p className="w-max justify-center text-center text-sm text-gray-400">
You can find it in your emergency kit you downloaded during signup.
</p>
<div className="mt-4 flex flex-row items-center justify-center md:mx-2 md:pb-4">
<p className="flex w-full px-4 text-center text-sm text-gray-400 sm:max-w-md">
You can find it in your emergency kit. You had to download the emergency kit during
signup.
</p>
</div>
<div className="mt-4 flex max-h-24 w-full items-center justify-center rounded-lg md:mt-0 md:max-h-28 md:p-2">
<div className="mt-8 w-1/4 min-w-[21.2rem] rounded-md text-center md:min-w-[20.1rem] lg:w-1/6">
<Controller
control={control}
name="backupKey"
@@ -75,12 +72,17 @@ export const InputBackupKeyStep = ({ verificationToken, onComplete }: Props) =>
)}
/>
</div>
<div className="mx-auto mt-4 flex max-h-20 w-full max-w-md flex-col items-center justify-center text-sm md:p-2">
<div className="text-l m-8 mt-6 px-8 py-3 text-lg">
<Button type="submit" colorSchema="secondary">
Submit Backup Key
</Button>
</div>
<div className="w-1/4 min-w-[21.2rem] rounded-md text-center md:min-w-[20.1rem] lg:w-1/6">
<Button
type="submit"
size="sm"
isFullWidth
className="h-10"
colorSchema="primary"
variant="solid"
>
Submit Backup Key
</Button>
</div>
</form>
);

View File

@@ -2,8 +2,7 @@ import { FormEvent, useState } from "react";
import { Helmet } from "react-helmet";
import { Link } from "@tanstack/react-router";
import InputField from "@app/components/basic/InputField";
import { Button, EmailServiceSetupModal } from "@app/components/v2";
import { Button, EmailServiceSetupModal, Input } from "@app/components/v2";
import { usePopUp } from "@app/hooks";
import { useSendPasswordResetEmail } from "@app/hooks/api";
import { useFetchServerStatus } from "@app/hooks/api/serverDetails";
@@ -44,9 +43,9 @@ export const VerifyEmailPage = () => {
};
return (
<div className="flex h-screen flex-col justify-start bg-bunker-800 px-6">
<div className="flex min-h-screen flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28">
<Helmet>
<title>Login</title>
<title>Reset Password</title>
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
<meta property="og:title" content="Verify your email in Infisical" />
@@ -56,66 +55,80 @@ export const VerifyEmailPage = () => {
/>
</Helmet>
<Link to="/">
<div className="mb-8 mt-20 flex cursor-pointer justify-center">
<div className="mb-4 mt-20 flex justify-center">
<img
src="/images/biglogo.png"
src="/images/gradientLogo.svg"
style={{
height: "90px",
width: "120px"
}}
alt="long logo"
alt="Infisical Logo"
/>
</div>
</Link>
{step === 1 && (
<form
onSubmit={onSubmit}
className="h-7/12 mx-auto w-full max-w-md rounded-xl bg-bunker px-6 py-4 pt-8 drop-shadow-xl"
className="mx-auto flex w-full flex-col items-center justify-center"
>
<p className="mx-auto mb-6 flex w-max justify-center text-2xl font-semibold text-bunker-100 md:text-3xl">
<h1 className="mb-2 bg-gradient-to-b from-white to-bunker-200 bg-clip-text text-center text-xl font-medium text-transparent">
Forgot your password?
</h1>
<p className="w-max justify-center text-center text-sm text-gray-400">
Enter your email to start the password reset process. <br /> You will receive an email
with instructions.
</p>
<div className="mt-4 flex flex-row items-center justify-center md:mx-2 md:pb-4">
<p className="flex w-max justify-center text-center text-sm text-gray-400">
Enter your email to start the password reset process. You will receive an email with
instructions.
</p>
</div>
<div className="mt-4 flex max-h-24 w-full items-center justify-center rounded-lg md:mt-0 md:max-h-28 md:p-2">
<InputField
label="Email"
onChangeHandler={setEmail}
type="email"
<div className="mt-8 w-1/4 min-w-[21.2rem] rounded-md text-center md:min-w-[20.1rem] lg:w-1/6">
<Input
value={email}
placeholder=""
onChange={(e) => setEmail(e.target.value)}
type="email"
placeholder="Enter your email..."
isRequired
autoComplete="username"
className="h-10"
/>
</div>
<div className="mx-auto mt-4 flex max-h-20 w-full max-w-md flex-col items-center justify-center text-sm md:p-2">
<div className="text-l m-8 mt-6 px-8 py-3 text-lg">
<Button type="submit" size="lg" onClick={() => {}} isLoading={loading}>
Continue
</Button>
</div>
<div className="mt-4 w-1/4 min-w-[21.2rem] rounded-md text-center md:min-w-[20.1rem] lg:w-1/6">
<Button
type="submit"
size="sm"
isFullWidth
className="h-10"
colorSchema="primary"
variant="solid"
isLoading={loading}
>
Continue
</Button>
</div>
<div className="mt-6 flex flex-row text-sm text-bunker-400">
<Link to="/login">
<span className="cursor-pointer duration-200 hover:text-bunker-200 hover:underline hover:decoration-primary-700 hover:underline-offset-4">
Back to Login
</span>
</Link>
</div>
</form>
)}
{step === 2 && (
<div className="h-7/12 mx-auto w-full max-w-md rounded-xl bg-bunker px-6 py-4 pt-8 drop-shadow-xl">
<p className="mx-auto mb-6 flex w-max justify-center text-xl font-semibold text-bunker-100 md:text-2xl">
Look for an email in your inbox.
<div className="mx-auto flex w-full flex-col items-center justify-center">
<h1 className="mb-2 bg-gradient-to-b from-white to-bunker-200 bg-clip-text text-center text-xl font-medium text-transparent">
Look for an email in your inbox
</h1>
<p className="w-max max-w-lg justify-center text-center text-sm text-gray-400">
If the email is in our system, you will receive an email at{" "}
<span className="italic">{email}</span> with instructions on how to reset your password.
</p>
<div className="mt-4 flex flex-row items-center justify-center md:mx-2 md:pb-4">
<p className="w-max text-center text-sm text-gray-400">
If the email is in our system, you will receive an email at{" "}
<span className="italic">{email}</span> with instructions on how to reset your
password.
</p>
<div className="mt-6 flex flex-row text-sm text-bunker-400">
<Link to="/login">
<span className="cursor-pointer duration-200 hover:text-bunker-200 hover:underline hover:decoration-primary-700 hover:underline-offset-4">
Back to Login
</span>
</Link>
</div>
</div>
)}
<EmailServiceSetupModal
isOpen={popUp.setUpEmail?.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("setUpEmail", isOpen)}