@b3dotfun/sdk 0.0.63 → 0.0.64-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/global-account/react/components/B3DynamicModal.js +7 -3
- package/dist/cjs/global-account/react/components/ManageAccount/BalanceContent.js +3 -3
- package/dist/cjs/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +6 -0
- package/dist/cjs/global-account/react/components/ProfileEditor/ProfileEditor.js +141 -0
- package/dist/cjs/global-account/react/components/index.d.ts +2 -0
- package/dist/cjs/global-account/react/components/index.js +7 -2
- package/dist/cjs/global-account/react/stores/useModalStore.d.ts +7 -1
- package/dist/cjs/global-account/react/utils/profileDisplay.d.ts +6 -0
- package/dist/cjs/global-account/react/utils/profileDisplay.js +60 -4
- package/dist/esm/global-account/react/components/B3DynamicModal.js +7 -3
- package/dist/esm/global-account/react/components/ManageAccount/BalanceContent.js +3 -3
- package/dist/esm/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +6 -0
- package/dist/esm/global-account/react/components/ProfileEditor/ProfileEditor.js +135 -0
- package/dist/esm/global-account/react/components/index.d.ts +2 -0
- package/dist/esm/global-account/react/components/index.js +3 -0
- package/dist/esm/global-account/react/stores/useModalStore.d.ts +7 -1
- package/dist/esm/global-account/react/utils/profileDisplay.d.ts +6 -0
- package/dist/esm/global-account/react/utils/profileDisplay.js +59 -4
- package/dist/types/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +6 -0
- package/dist/types/global-account/react/components/index.d.ts +2 -0
- package/dist/types/global-account/react/stores/useModalStore.d.ts +7 -1
- package/dist/types/global-account/react/utils/profileDisplay.d.ts +6 -0
- package/package.json +2 -2
- package/src/global-account/react/components/B3DynamicModal.tsx +7 -3
- package/src/global-account/react/components/ManageAccount/BalanceContent.tsx +4 -4
- package/src/global-account/react/components/ProfileEditor/ProfileEditor.tsx +265 -0
- package/src/global-account/react/components/index.ts +4 -0
- package/src/global-account/react/stores/useModalStore.ts +9 -1
- package/src/global-account/react/utils/profileDisplay.ts +67 -4
|
@@ -1,5 +1,68 @@
|
|
|
1
|
+
import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
|
|
1
2
|
import { type Profile } from "thirdweb/wallets";
|
|
2
3
|
|
|
4
|
+
const debug = debugB3React("profileDisplay");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Validates that an image URL uses an allowed schema
|
|
8
|
+
* @param url - The URL to validate
|
|
9
|
+
* @returns The URL if valid, null otherwise
|
|
10
|
+
*/
|
|
11
|
+
export function validateImageUrl(url: string | null | undefined): string | null {
|
|
12
|
+
if (!url) return null;
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
// For blob URLs (from createObjectURL)
|
|
16
|
+
if (url.startsWith("blob:")) {
|
|
17
|
+
return url;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// For IPFS protocol URLs
|
|
21
|
+
if (url.startsWith("ipfs://")) {
|
|
22
|
+
return url;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Parse URL to validate protocol and hostname
|
|
26
|
+
const parsedUrl = new URL(url);
|
|
27
|
+
|
|
28
|
+
// Only allow http and https protocols
|
|
29
|
+
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
|
|
30
|
+
debug("Rejected unsafe protocol:", parsedUrl.protocol, url);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Whitelist of allowed IPFS gateway hostnames
|
|
35
|
+
const allowedIpfsGateways = [
|
|
36
|
+
"ipfs.io",
|
|
37
|
+
"gateway.pinata.cloud",
|
|
38
|
+
"cloudflare-ipfs.com",
|
|
39
|
+
"dweb.link",
|
|
40
|
+
"nftstorage.link",
|
|
41
|
+
"w3s.link",
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
// Check if hostname matches allowed IPFS gateways
|
|
45
|
+
const hostname = parsedUrl.hostname.toLowerCase();
|
|
46
|
+
const isAllowedIpfsGateway = allowedIpfsGateways.some(gateway => {
|
|
47
|
+
// Exact match or subdomain of the gateway
|
|
48
|
+
return hostname === gateway || hostname.endsWith(`.${gateway}`);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (isAllowedIpfsGateway) {
|
|
52
|
+
return url;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// For standard HTTP(S) URLs from trusted sources
|
|
56
|
+
// Add additional hostname validation here if needed
|
|
57
|
+
// For now, allow all HTTP(S) URLs (can be restricted further if needed)
|
|
58
|
+
return url;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
// Invalid URL format
|
|
61
|
+
debug("Invalid image URL format:", url, error);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
3
66
|
export interface ExtendedProfileDetails {
|
|
4
67
|
id?: string;
|
|
5
68
|
email?: string;
|
|
@@ -40,7 +103,7 @@ export function getProfileDisplayInfo(profile: ExtendedProfile): ProfileDisplayI
|
|
|
40
103
|
displayInfo = {
|
|
41
104
|
title: details.name || details.username || "Unknown",
|
|
42
105
|
subtitle: details.username ? `@${details.username}` : "X Account",
|
|
43
|
-
imageUrl: details.profileImageUrl
|
|
106
|
+
imageUrl: validateImageUrl(details.profileImageUrl),
|
|
44
107
|
initial: "X",
|
|
45
108
|
type,
|
|
46
109
|
};
|
|
@@ -49,7 +112,7 @@ export function getProfileDisplayInfo(profile: ExtendedProfile): ProfileDisplayI
|
|
|
49
112
|
displayInfo = {
|
|
50
113
|
title: details.name || details.username || "Unknown",
|
|
51
114
|
subtitle: details.username ? `@${details.username}` : "Farcaster Account",
|
|
52
|
-
imageUrl: details.profileImageUrl
|
|
115
|
+
imageUrl: validateImageUrl(details.profileImageUrl),
|
|
53
116
|
initial: "F",
|
|
54
117
|
type,
|
|
55
118
|
};
|
|
@@ -58,7 +121,7 @@ export function getProfileDisplayInfo(profile: ExtendedProfile): ProfileDisplayI
|
|
|
58
121
|
displayInfo = {
|
|
59
122
|
title: details.name || details.email || "Unknown",
|
|
60
123
|
subtitle: details.email || "Google Account",
|
|
61
|
-
imageUrl: details.profileImageUrl
|
|
124
|
+
imageUrl: validateImageUrl(details.profileImageUrl),
|
|
62
125
|
initial: "G",
|
|
63
126
|
type,
|
|
64
127
|
};
|
|
@@ -67,7 +130,7 @@ export function getProfileDisplayInfo(profile: ExtendedProfile): ProfileDisplayI
|
|
|
67
130
|
displayInfo = {
|
|
68
131
|
title: details.username || details.name || "Unknown",
|
|
69
132
|
subtitle: "Discord Account",
|
|
70
|
-
imageUrl: details.profileImageUrl
|
|
133
|
+
imageUrl: validateImageUrl(details.profileImageUrl),
|
|
71
134
|
initial: "D",
|
|
72
135
|
type,
|
|
73
136
|
};
|