diff --git a/frontend/src/components/ProfileManager.jsx b/frontend/src/components/ProfileManager.jsx index 987c9983..d6bbb4db 100644 --- a/frontend/src/components/ProfileManager.jsx +++ b/frontend/src/components/ProfileManager.jsx @@ -9,7 +9,24 @@ import { } from '@stacks/transactions'; import { network, appDetails, getSenderAddress } from '../utils/stacks'; import { CONTRACT_ADDRESS, CONTRACT_NAME, FN_GET_PROFILE, FN_UPDATE_PROFILE } from '../config/contracts'; -import { User, Save, Loader2 } from 'lucide-react'; +import { User, Save, Loader2, ImageOff } from 'lucide-react'; + +/** + * Validate that a URL is safe to render as an avatar image. + * Only HTTPS URLs are accepted to prevent tracking pixels, + * data: URI abuse, and internal network probes. + * @param {string} url + * @returns {boolean} + */ +function isValidAvatarUrl(url) { + if (!url) return false; + try { + const parsed = new URL(url); + return parsed.protocol === 'https:'; + } catch { + return false; + } +} export default function ProfileManager({ addToast }) { const [displayName, setDisplayName] = useState(''); @@ -29,6 +46,7 @@ export default function ProfileManager({ addToast }) { fetchProfile(); }, [senderAddress]); + /** Fetch the existing on-chain profile for the connected wallet. */ const fetchProfile = async () => { try { setLoading(true); @@ -56,6 +74,7 @@ export default function ProfileManager({ addToast }) { } }; + /** Validate all form fields before submission. */ const validateForm = () => { if (!displayName.trim()) { addToast?.('Display name is required', 'warning'); @@ -73,9 +92,14 @@ export default function ProfileManager({ addToast }) { addToast?.('Avatar URL must be 256 characters or fewer', 'warning'); return false; } + if (avatarUrl && !isValidAvatarUrl(avatarUrl)) { + addToast?.('Avatar URL must use HTTPS', 'warning'); + return false; + } return true; }; + /** Submit the profile update transaction to the wallet. */ const handleSaveProfile = async () => { if (!validateForm()) return; @@ -113,7 +137,7 @@ export default function ProfileManager({ addToast }) { if (loading) { return ( -
Preview
+ Avatar URL must use HTTPS +
+