mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 14:27:30 +00:00
Changed "token" param to "hash" and used hex encoding for URL
This commit is contained in:
@@ -64,7 +64,7 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
|
|||||||
hashedHex: z.string().min(1).optional(),
|
hashedHex: z.string().min(1).optional(),
|
||||||
password: z.string().optional(),
|
password: z.string().optional(),
|
||||||
email: z.string().optional(),
|
email: z.string().optional(),
|
||||||
token: z.string().optional()
|
hash: z.string().optional()
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -92,7 +92,7 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
|
|||||||
password: req.body.password,
|
password: req.body.password,
|
||||||
orgId: req.permission?.orgId,
|
orgId: req.permission?.orgId,
|
||||||
email: req.body.email,
|
email: req.body.email,
|
||||||
token: req.body.token
|
hash: req.body.hash
|
||||||
});
|
});
|
||||||
|
|
||||||
if (sharedSecret.secret?.orgId) {
|
if (sharedSecret.secret?.orgId) {
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ export const secretSharingServiceFactory = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate salt for signing email tokens (if emails are provided)
|
// Generate salt for signing email hashes (if emails are provided)
|
||||||
salt = crypto.randomBytes(32).toString("hex");
|
salt = crypto.randomBytes(32).toString("hex");
|
||||||
encryptedSalt = encryptWithRoot(Buffer.from(salt));
|
encryptedSalt = encryptWithRoot(Buffer.from(salt));
|
||||||
}
|
}
|
||||||
@@ -159,7 +159,7 @@ export const secretSharingServiceFactory = ({
|
|||||||
for await (const email of emails) {
|
for await (const email of emails) {
|
||||||
try {
|
try {
|
||||||
const hmac = crypto.createHmac("sha256", salt).update(email);
|
const hmac = crypto.createHmac("sha256", salt).update(email);
|
||||||
const token = hmac.digest("base64");
|
const hash = hmac.digest("hex");
|
||||||
|
|
||||||
// Only show the username to emails which are part of the organization
|
// Only show the username to emails which are part of the organization
|
||||||
const respondentUsername = orgEmails.includes(email) ? user.username : undefined;
|
const respondentUsername = orgEmails.includes(email) ? user.username : undefined;
|
||||||
@@ -170,7 +170,7 @@ export const secretSharingServiceFactory = ({
|
|||||||
substitutions: {
|
substitutions: {
|
||||||
name,
|
name,
|
||||||
respondentUsername,
|
respondentUsername,
|
||||||
secretRequestUrl: `${appCfg.SITE_URL}/shared/secret/${idToReturn}?email=${encodeURIComponent(email)}&token=${token}`
|
secretRequestUrl: `${appCfg.SITE_URL}/shared/secret/${idToReturn}?email=${encodeURIComponent(email)}&hash=${hash}`
|
||||||
},
|
},
|
||||||
template: SmtpTemplates.SecretRequestCompleted
|
template: SmtpTemplates.SecretRequestCompleted
|
||||||
});
|
});
|
||||||
@@ -460,7 +460,7 @@ export const secretSharingServiceFactory = ({
|
|||||||
orgId,
|
orgId,
|
||||||
password,
|
password,
|
||||||
email,
|
email,
|
||||||
token
|
hash
|
||||||
}: TGetActiveSharedSecretByIdDTO) => {
|
}: TGetActiveSharedSecretByIdDTO) => {
|
||||||
const sharedSecret = isUuidV4(sharedSecretId)
|
const sharedSecret = isUuidV4(sharedSecretId)
|
||||||
? await secretSharingDAL.findOne({
|
? await secretSharingDAL.findOne({
|
||||||
@@ -512,22 +512,22 @@ export const secretSharingServiceFactory = ({
|
|||||||
|
|
||||||
if (sharedSecret.authorizedEmails && sharedSecret.encryptedSalt) {
|
if (sharedSecret.authorizedEmails && sharedSecret.encryptedSalt) {
|
||||||
// Verify both params were passed
|
// Verify both params were passed
|
||||||
if (!email || !token) {
|
if (!email || !hash) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "This secret is email protected. Parameters must include email and token."
|
message: "This secret is email protected. Parameters must include email and hash."
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify that email is authorized to view shared secret
|
// Verify that email is authorized to view shared secret
|
||||||
} else if (!(sharedSecret.authorizedEmails as string[]).includes(email)) {
|
} else if (!(sharedSecret.authorizedEmails as string[]).includes(email)) {
|
||||||
throw new UnauthorizedError({ message: "Email not authorized to view secret" });
|
throw new UnauthorizedError({ message: "Email not authorized to view secret" });
|
||||||
|
|
||||||
// Verify that token matches
|
// Verify that hash matches
|
||||||
} else {
|
} else {
|
||||||
const salt = decryptWithRoot(sharedSecret.encryptedSalt).toString();
|
const salt = decryptWithRoot(sharedSecret.encryptedSalt).toString();
|
||||||
const hmac = crypto.createHmac("sha256", salt).update(email);
|
const hmac = crypto.createHmac("sha256", salt).update(email);
|
||||||
const rebuiltToken = hmac.digest("base64");
|
const rebuiltHash = hmac.digest("hex");
|
||||||
|
|
||||||
if (rebuiltToken !== token) {
|
if (rebuiltHash !== hash) {
|
||||||
throw new UnauthorizedError({ message: "Email not authorized to view secret" });
|
throw new UnauthorizedError({ message: "Email not authorized to view secret" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export type TGetActiveSharedSecretByIdDTO = {
|
|||||||
|
|
||||||
// For secrets shared with specific emails
|
// For secrets shared with specific emails
|
||||||
email?: string;
|
email?: string;
|
||||||
token?: string;
|
hash?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TValidateActiveSharedSecretDTO = TGetActiveSharedSecretByIdDTO & {
|
export type TValidateActiveSharedSecretDTO = TGetActiveSharedSecretByIdDTO & {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const secretSharingKeys = {
|
|||||||
hashedHex: string | null;
|
hashedHex: string | null;
|
||||||
password?: string;
|
password?: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
token?: string;
|
hash?: string;
|
||||||
}) => ["shared-secret", arg],
|
}) => ["shared-secret", arg],
|
||||||
getSecretRequestById: (arg: { id: string }) => ["secret-request", arg] as const
|
getSecretRequestById: (arg: { id: string }) => ["secret-request", arg] as const
|
||||||
};
|
};
|
||||||
@@ -75,7 +75,7 @@ export const useGetActiveSharedSecretById = ({
|
|||||||
hashedHex,
|
hashedHex,
|
||||||
password,
|
password,
|
||||||
email,
|
email,
|
||||||
token
|
hash
|
||||||
}: {
|
}: {
|
||||||
sharedSecretId: string;
|
sharedSecretId: string;
|
||||||
hashedHex: string | null;
|
hashedHex: string | null;
|
||||||
@@ -83,7 +83,7 @@ export const useGetActiveSharedSecretById = ({
|
|||||||
|
|
||||||
// For secrets shared to specific emails (optional)
|
// For secrets shared to specific emails (optional)
|
||||||
email?: string;
|
email?: string;
|
||||||
token?: string;
|
hash?: string;
|
||||||
}) => {
|
}) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: secretSharingKeys.getSecretById({
|
queryKey: secretSharingKeys.getSecretById({
|
||||||
@@ -91,7 +91,7 @@ export const useGetActiveSharedSecretById = ({
|
|||||||
hashedHex,
|
hashedHex,
|
||||||
password,
|
password,
|
||||||
email,
|
email,
|
||||||
token
|
hash
|
||||||
}),
|
}),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await apiRequest.post<TViewSharedSecretResponse>(
|
const { data } = await apiRequest.post<TViewSharedSecretResponse>(
|
||||||
@@ -100,7 +100,7 @@ export const useGetActiveSharedSecretById = ({
|
|||||||
...(hashedHex && { hashedHex }),
|
...(hashedHex && { hashedHex }),
|
||||||
password,
|
password,
|
||||||
email,
|
email,
|
||||||
token
|
hash
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ export const ViewSharedSecretByIDPage = () => {
|
|||||||
from: ROUTE_PATHS.Public.ViewSharedSecretByIDPage.id,
|
from: ROUTE_PATHS.Public.ViewSharedSecretByIDPage.id,
|
||||||
select: (el) => el.email
|
select: (el) => el.email
|
||||||
});
|
});
|
||||||
const token = useSearch({
|
const hash = useSearch({
|
||||||
from: ROUTE_PATHS.Public.ViewSharedSecretByIDPage.id,
|
from: ROUTE_PATHS.Public.ViewSharedSecretByIDPage.id,
|
||||||
select: (el) => el.token
|
select: (el) => el.hash
|
||||||
});
|
});
|
||||||
const [password, setPassword] = useState<string>();
|
const [password, setPassword] = useState<string>();
|
||||||
const { hashedHex, key } = extractDetailsFromUrl(urlEncodedKey);
|
const { hashedHex, key } = extractDetailsFromUrl(urlEncodedKey);
|
||||||
@@ -59,7 +59,7 @@ export const ViewSharedSecretByIDPage = () => {
|
|||||||
hashedHex,
|
hashedHex,
|
||||||
password,
|
password,
|
||||||
email,
|
email,
|
||||||
token
|
hash
|
||||||
});
|
});
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ViewSharedSecretByIDPage } from "./ViewSharedSecretByIDPage";
|
|||||||
const SharedSecretByIDPageQuerySchema = z.object({
|
const SharedSecretByIDPageQuerySchema = z.object({
|
||||||
key: z.string().catch(""),
|
key: z.string().catch(""),
|
||||||
email: z.string().optional(),
|
email: z.string().optional(),
|
||||||
token: z.string().optional()
|
hash: z.string().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Route = createFileRoute("/shared/secret/$secretId")({
|
export const Route = createFileRoute("/shared/secret/$secretId")({
|
||||||
|
|||||||
Reference in New Issue
Block a user