-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathens.ts
More file actions
139 lines (124 loc) · 3.61 KB
/
ens.ts
File metadata and controls
139 lines (124 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import { l1Provider } from "@lib/chains";
import { formatAddress } from "@lib/utils";
import sanitizeHtml from "sanitize-html";
import {
GithubHandleSchema,
TwitterHandleSchema,
WebUrlSchema,
} from "./schemas/common";
import { EnsAvatarProviderSchema, EnsTextRecordSchema } from "./schemas/ens";
import { EnsIdentity } from "./types/get-ens";
const sanitizeOptions: sanitizeHtml.IOptions = {
allowedTags: [
"b",
"i",
"em",
"strong",
"a",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"div",
"hr",
"li",
"ol",
"p",
"pre",
"ul",
"br",
"code",
"span",
],
disallowedTagsMode: "discard",
allowedAttributes: {
a: ["href"],
},
// Lots of these won't come up by default because we don't allow them
selfClosing: [
"img",
"br",
"hr",
"area",
"base",
"basefont",
"input",
"link",
"meta",
],
// URL schemes we permit
allowedSchemes: ["https", "mailto", "tel"],
allowedSchemesByTag: {},
allowedSchemesAppliedToAttributes: ["href", "src", "cite"],
allowProtocolRelative: false,
enforceHtmlBoundary: true,
};
export const getEnsForAddress = async (address: string | null | undefined) => {
const idShort = address?.replace(address?.slice(6, 38), "…");
const name = address ? await l1Provider.lookupAddress(address) : null;
if (name) {
const resolver = await l1Provider.getResolver(name);
const [descriptionRaw, urlRaw, twitterRaw, githubRaw, avatarRaw] =
await Promise.all([
resolver?.getText("description"),
resolver?.getText("url"),
resolver?.getText("com.twitter"),
resolver?.getText("com.github"),
resolver?.getAvatar(),
]);
// Validate all ENS provider responses with graceful fallback
// If validation fails, we set the field to null rather than crashing
const descriptionValidation = EnsTextRecordSchema.safeParse(descriptionRaw);
const urlValidation = WebUrlSchema.nullable().safeParse(urlRaw);
const twitterValidation =
TwitterHandleSchema.nullable().safeParse(twitterRaw);
const githubValidation = GithubHandleSchema.nullable().safeParse(githubRaw);
const avatarValidation = EnsAvatarProviderSchema.safeParse(avatarRaw);
const description = descriptionValidation.success
? descriptionValidation.data
: null;
const url = urlValidation.success ? urlValidation.data : null;
const twitter = twitterValidation.success ? twitterValidation.data : null;
const github = githubValidation.success ? githubValidation.data : null;
const avatar = avatarValidation.success ? avatarValidation.data : null;
const ens: EnsIdentity = {
id: address ?? "",
idShort: idShort ?? "",
name: name ?? null,
description: sanitizeHtml(nl2br(description), sanitizeOptions),
url,
twitter,
github,
avatar: avatar?.url ? `/api/ens-data/image/${name}` : null,
};
return ens;
}
const ens: EnsIdentity = {
id: address ?? "",
idShort: idShort ?? "",
name: null,
};
return ens;
};
export const nl2br = (str, is_xhtml = true) => {
if (typeof str === "undefined" || str === null) {
return "";
}
const breakTag =
is_xhtml || typeof is_xhtml === "undefined" ? "<br />" : "<br>";
return (str + "").replace(
/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g,
"$1" + breakTag + "$2"
);
};
export const getEnsForVotes = async (address: string | null | undefined) => {
const idShort = formatAddress(address);
const name = address ? await l1Provider.lookupAddress(address) : null;
return {
id: address ?? "",
idShort: idShort ?? "",
name,
};
};