feat: secure combined uploads and update UI components

Changes:
- Secure uploadUtilBillsProofOfPayment with checksum validation
- Update ViewLocationCard to accept and use shareId prop
- Update ViewBillCard to accept shareId and use it for uploads
- Update ViewBillBadge to pass shareId to bill detail pages
- Add client-side validation check for shareId before upload
- Update back button links to use shareId

Security improvements:
- Both per-bill and combined uploads now validate checksum and TTL
- IP-based rate limiting applied to both upload types
- PDF magic bytes validation for both upload types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Knee Cola
2025-12-08 00:25:26 +01:00
parent 844e386e18
commit 81dddb526a
4 changed files with 102 additions and 49 deletions

View File

@@ -5,18 +5,22 @@ import { TicketIcon } from "@heroicons/react/24/outline";
import { useLocale } from "next-intl";
export interface ViewBillBadgeProps {
locationId: string,
bill: Bill
locationId: string;
shareId?: string;
bill: Bill;
};
export const ViewBillBadge: FC<ViewBillBadgeProps> = ({ locationId, bill: { _id: billId, name, paid, attachment, proofOfPayment } }) => {
export const ViewBillBadge: FC<ViewBillBadgeProps> = ({ locationId, shareId, bill: { _id: billId, name, paid, attachment, proofOfPayment } }) => {
const currentLocale = useLocale();
const className = `badge badge-lg p-[1em] ${paid ? "badge-success" : " badge-outline"} ${!paid && !!attachment ? "btn-outline btn-success" : ""} cursor-pointer`;
// Use shareId if available (for shared views), otherwise use locationId (for owner views)
const billPageId = shareId || locationId;
return (
<Link href={`/${currentLocale}//share/bill/${locationId}-${billId}`} className={className}>
<Link href={`/${currentLocale}//share/bill/${billPageId}-${billId}`} className={className}>
{name}
{
proofOfPayment?.uploadedAt ?