Skip to content

Commit

Permalink
Merge pull request #51 from ensdomains/mdt/restricted-content-type
Browse files Browse the repository at this point in the history
restrict content-type, file size limit
  • Loading branch information
mdtanrikulu authored Sep 26, 2024
2 parents 788f0f2 + f7a4e25 commit 4c81390
Show file tree
Hide file tree
Showing 14 changed files with 885 additions and 249 deletions.
8 changes: 6 additions & 2 deletions example/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,12 @@ function fadeImg() {
this.style.opacity = '1';
}

function setImage(ens, avatarUri = notFoundImage, warn = false) {
function setImage(ens, avatarUri = notFoundImage, warn = false, headerUri) {
const elem = document.getElementById('queryImage');
const headerContainer = document.getElementById('headerContainer');
elem.setAttribute('src', avatarUri);
elem.setAttribute('alt', ens);
headerContainer.style.backgroundImage = headerUri ? `url("${headerUri}")` : 'none';
const warnText = document.getElementById('warnText');
if (warn) {
if (warnText) return;
Expand Down Expand Up @@ -112,7 +114,9 @@ document.getElementById('queryInput').addEventListener('change', event => {
.getMetadata(ens)
.then(metadata => {
const avatar = avtUtils.getImageURI({ metadata });
setImage(ens, avatar);
avt.getHeader(ens).then(header => {
setImage(ens, avatar, false, header);
});
elem.style.filter = 'none';
})
.catch(error => {
Expand Down
14 changes: 12 additions & 2 deletions example/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ const IPFS = 'https://cf-ipfs.com';
const provider = new StaticJsonRpcProvider(
`https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`
);
const avt = new AvatarResolver(provider, { ipfs: IPFS, apiKey: { opensea: process.env.OPENSEA_KEY }});
const avt = new AvatarResolver(provider, {
ipfs: IPFS,
apiKey: { opensea: process.env.OPENSEA_KEY },
});
avt
.getMetadata(ensName)
.then(metadata => {
Expand All @@ -30,6 +33,13 @@ avt
},
jsdomWindow: jsdom,
});
console.log(avatar);
console.log('avatar: ', avatar);
})
.catch(console.log);

avt
.getHeader(ensName)
.then(header => {
console.log('header: ', header);
})
.catch(console.log);
41 changes: 29 additions & 12 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,28 @@
<div class="container">
<div id="avatars"></div>
<div class="queryContainer">
<h2>Query ENS Avatar</h2>
<div>
<img class="queryImage" id="queryImage" width="300" height="300" src="./example/ens.png" />
<div id="headerContainer">
<h2>Query ENS Avatar</h2>
<div>
<input
class="queryInput"
id="queryInput"
type="text"
placeholder="vitalik.eth"
autofocus
autocomplete="off"
<img
class="queryImage"
id="queryImage"
width="300"
height="300"
src="./example/ens.png"
/>
<div class="hint">
(type ENS name and hit the enter button)
<div>
<input
class="queryInput"
id="queryInput"
type="text"
placeholder="vitalik.eth"
autofocus
autocomplete="off"
/>
<div class="hint">
(type ENS name and hit the enter button)
</div>
</div>
</div>
</div>
Expand All @@ -49,6 +57,12 @@ <h2>Query ENS Avatar</h2>
pointer-events: none;
user-select: none;
}
#headerContainer {
height: 100%;
background-position: 0 55px;
background-repeat: no-repeat;
background-size: contain;
}
.hint {
margin-top: 0.5rem;
color: #aaa;
Expand Down Expand Up @@ -76,6 +90,9 @@ <h2>Query ENS Avatar</h2>
}
.queryImage {
object-fit: contain;
border: 5px solid white;
border-radius: 5px;
outline: #d6d6d6 solid 2px;
}
.queryInput {
width: 19rem;
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.0.0-alpha.3.ethers.6",
"version": "1.0.1",
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.esm.js",
Expand Down Expand Up @@ -57,9 +57,11 @@
"@size-limit/preset-small-lib": "^11.0.1",
"@types/dompurify": "^3.0.5",
"@types/jsdom": "^21.1.6",
"@types/moxios": "^0.4.17",
"@types/url-join": "^4.0.1",
"dotenv": "^16.3.1",
"esbuild": "^0.14.21",
"moxios": "^0.4.0",
"nock": "^13.2.2",
"rollup": "^4.9.1",
"size-limit": "^11.0.1",
Expand Down
50 changes: 40 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import {
isImageURI,
parseNFT,
} from './utils';
import { AvatarRequestOpts, AvatarResolverOpts, Spec } from './types';
import {
AvatarRequestOpts,
AvatarResolverOpts,
HeaderRequestOpts,
Spec,
} from './types';

export const specs: { [key: string]: new () => Spec } = Object.freeze({
erc721: ERC721,
Expand All @@ -23,10 +28,14 @@ export const specs: { [key: string]: new () => Spec } = Object.freeze({
export interface UnsupportedNamespace {}
export class UnsupportedNamespace extends BaseError {}

export interface UnsupportedMediaKey {}
export class UnsupportedMediaKey extends BaseError {}

export interface AvatarResolver {
provider: JsonRpcProvider;
options?: AvatarResolverOpts;
getAvatar(ens: string, data: AvatarRequestOpts): Promise<string | null>;
getHeader(ens: string, data: HeaderRequestOpts): Promise<string | null>;
getMetadata(ens: string): Promise<any | null>;
}

Expand All @@ -40,9 +49,13 @@ export class AvatarResolver implements AvatarResolver {
if (options?.agents) {
createAgentAdapter(fetch, options?.agents);
}

if (options?.maxContentLength && options?.maxContentLength > 0) {
fetch.defaults.maxContentLength = options?.maxContentLength;
}
}

async getMetadata(ens: string) {
async getMetadata(ens: string, key: string = 'avatar') {
// retrieve registrar address and resolver object from ens name
const [resolvedAddress, resolver] = await handleSettled([
this.provider.resolveName(ens),
Expand All @@ -51,20 +64,18 @@ export class AvatarResolver implements AvatarResolver {
if (!resolver) return null;

// retrieve 'avatar' text recored from resolver
const avatarURI = await resolver.getText('avatar');
if (!avatarURI) return null;
const mediaURI = await resolver.getText(key);
if (!mediaURI) return null;

// test case-insensitive in case of uppercase records
if (!/eip155:/i.test(avatarURI)) {
if (!/eip155:/i.test(mediaURI)) {
const uriSpec = new URI();
const metadata = await uriSpec.getMetadata(avatarURI, this.options);
const metadata = await uriSpec.getMetadata(mediaURI, this.options);
return { uri: ens, ...metadata };
}

// parse retrieved avatar uri
const { chainID, namespace, contractAddress, tokenID } = parseNFT(
avatarURI
);
const { chainID, namespace, contractAddress, tokenID } = parseNFT(mediaURI);
// detect avatar spec by namespace
const Spec = specs[namespace];
if (!Spec)
Expand Down Expand Up @@ -95,7 +106,26 @@ export class AvatarResolver implements AvatarResolver {
ens: string,
data?: AvatarRequestOpts
): Promise<string | null> {
const metadata = await this.getMetadata(ens);
return this._getMedia(ens, 'avatar', data);
}

async getHeader(
ens: string,
data?: HeaderRequestOpts
): Promise<string | null> {
const mediaKey = data?.mediaKey || 'header';
if (!['header', 'banner'].includes(mediaKey)) {
throw new UnsupportedMediaKey('Unsupported media key');
}
return this._getMedia(ens, mediaKey, data);
}

async _getMedia(
ens: string,
mediaKey: string = 'avatar',
data?: HeaderRequestOpts
) {
const metadata = await this.getMetadata(ens, mediaKey);
if (!metadata) return null;
const imageURI = getImageURI({
metadata,
Expand Down
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,18 @@ export interface AvatarResolverOpts {
apiKey?: MarketplaceAPIKey;
urlDenyList?: string[];
agents?: AxiosAgents;
maxContentLength?: number;
}

export interface AvatarRequestOpts {
jsdomWindow?: any;
}

export interface HeaderRequestOpts {
jsdomWindow?: any;
mediaKey?: 'header' | 'banner';
}

export type Gateways = {
ipfs?: string;
arweave?: string;
Expand Down
3 changes: 3 additions & 0 deletions src/utils/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ export function createCacheAdapter(fetch: Axios, ttl: number) {
function createFetcher({
ttl,
agents,
maxContentLength,
}: {
ttl?: number;
agents?: AxiosAgents;
maxContentLength?: number;
}) {
const _fetch = axios.create({
proxy: false,
...(maxContentLength && { maxContentLength }),
});
if (ttl && ttl > 0) {
createCacheAdapter(_fetch, ttl);
Expand Down
3 changes: 2 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import { convertToRawSVG, getImageURI } from './getImageURI';
import { resolveURI } from './resolveURI';
import { createAgentAdapter, createCacheAdapter, fetch } from './fetch';
import { isCID } from './isCID';
import { isImageURI } from './isImageURI';
import { ALLOWED_IMAGE_MIMETYPES, isImageURI } from './isImageURI';

export {
ALLOWED_IMAGE_MIMETYPES,
BaseError,
assert,
convertToRawSVG,
Expand Down
Loading

0 comments on commit 4c81390

Please sign in to comment.