Skip to content

Commit

Permalink
Merge pull request #181 from ensdomains/mdt/iframe-sandbox
Browse files Browse the repository at this point in the history
introduce iframe-sandboxing
  • Loading branch information
mdtanrikulu authored Sep 24, 2024
2 parents 4d114cb + cf71cff commit f039865
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 20 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"dependencies": {
"@adraffy/ens-normalize": "^1.10.0",
"@ensdomains/ens-avatar": "^1.0.0-alpha.3.ethers.6",
"@ensdomains/ens-avatar": "^1.0.0",
"@ensdomains/ensjs": "^3.7.0",
"@types/lodash": "^4.14.170",
"btoa": "^1.2.1",
Expand Down
5 changes: 4 additions & 1 deletion src/controller/ensImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export async function ensImage(req: Request, res: Response) {
// #swagger.parameters['{}'] = { name: 'contractAddress', description: 'Contract address which stores the NFT indicated by the tokenId', type: 'string', schema: { $ref: '#/definitions/contractAddress' } }
// #swagger.parameters['tokenId'] = { type: 'string', description: 'Labelhash(v1) /Namehash(v2) of your ENS name.\n\nMore: https://docs.ens.domains/contract-api-reference/name-processing#hashing-names', schema: { $ref: '#/definitions/tokenId' } }
res.setTimeout(RESPONSE_TIMEOUT, () => {
res.status(504).json({ message: 'Timeout' });
if (!res.headersSent) {
res.status(504).json({ message: 'Timeout' });
return;
}
});

const { contractAddress, networkName, tokenId: identifier } = req.params;
Expand Down
3 changes: 2 additions & 1 deletion src/controller/ensMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ export async function ensMetadata(req: Request, res: Response) {
});

const { contractAddress, networkName, tokenId: identifier } = req.params;
const { provider, SUBGRAPH_URL } = getNetwork(networkName as NetworkName);
const last_request_date = Date.now();
let tokenId, version;
let provider, SUBGRAPH_URL;
try {
({ provider, SUBGRAPH_URL } = getNetwork(networkName as NetworkName));
({ tokenId, version } = await checkContract(
provider,
contractAddress,
Expand Down
19 changes: 14 additions & 5 deletions src/service/avatar.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import http from 'http';
import https from 'https';

import { AvatarResolver } from '@ensdomains/ens-avatar';
import { AvatarResolver, utils } from '@ensdomains/ens-avatar';
import { strict as assert } from 'assert';
import { JsonRpcProvider } from 'ethers';
import createDOMPurify from 'dompurify';
Expand All @@ -18,6 +18,7 @@ import isSvg from '../utils/isSvg';
const { requestFilterHandler } = require('ssrf-req-filter');

const window = new JSDOM('').window;
const { ALLOWED_IMAGE_MIMETYPES } = utils;

interface HostMeta {
chain_id? : number;
Expand Down Expand Up @@ -97,14 +98,18 @@ export class AvatarMetadata {
headers: {
'user-agent': 'ENS-ImageFetcher/1.0.0',
},
})

});

assert(!!response, 'Response is empty');

const mimeType = response?.headers.get('Content-Type') || '';
const data = await response?.buffer();

assert(
ALLOWED_IMAGE_MIMETYPES.includes(mimeType),
'Mimetype is not supported'
);

if (mimeType?.includes('svg') || isSvg(data.toString())) {
const DOMPurify = createDOMPurify(window);
const cleanData = DOMPurify.sanitize(data.toString(), {
Expand All @@ -121,8 +126,12 @@ export class AvatarMetadata {
const mimeType = avatarURI.match(/[^:]\w+\/[\w-+\d.]+(?=;|,)/);
const base64data = avatarURI.split('base64,')[1];

assert(base64data, 'base64 format is incorrect: empty data');
assert(mimeType, 'base64 format is incorrect: no mimetype');
assert(base64data, 'Base64 format is incorrect: Empty data');
assert(mimeType, 'Base64 format is incorrect: No mimetype');
assert(
ALLOWED_IMAGE_MIMETYPES.includes(mimeType[0]),
'Mimetype is not supported'
);

const data = Buffer.from(base64data, 'base64');
return [data, mimeType[0]];
Expand Down
30 changes: 22 additions & 8 deletions src/template-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,20 @@ export default function createDocumentfromTemplate({
padding: 0 25px;
box-sizing: border-box;
}
.preview img {
object-fit: cover;
.container {
position: relative;
overflow: hidden;
width: 100%;
}
#imgSource {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
user-select: none !important;
pointer-events: none !important;
}
Expand Down Expand Up @@ -236,15 +245,20 @@ export default function createDocumentfromTemplate({
</svg>
</div>
<div class="preview">
<div id="imgSource">
${
mimeType !== 'image/svg+xml'
? `<img
<div class="container">
<iframe srcdoc="${(mimeType !== 'image/svg+xml'
? `<img
src="${image}"
alt="${metadata.name}"
style="width:100%;"
/>`
: buffer
}
: "<div style='width:100%;'>" + buffer?.toString() + '</div>' || ''
).replace(/"/g, "'")}"
sandbox="allow-same-origin"
id="imgSource"
frameborder="0"
scrolling="no">
</iframe>
</div>
<div class="docs">
<div>
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,10 @@
dns-packet "^5.6.1"
typescript-logging "^1.0.1"

"@ensdomains/ens-avatar@^1.0.0-alpha.3.ethers.6":
version "1.0.0-alpha.3.ethers.6"
resolved "https://registry.yarnpkg.com/@ensdomains/ens-avatar/-/ens-avatar-1.0.0-alpha.3.ethers.6.tgz#7a0707a4608044340427d21cb27ed317563abe89"
integrity sha512-CLO2xIace+9pZygKbw+6Kt1qSwhx86m/L9hpQSEjqbOqPX2Wph4LVX84D07bFzI7oTRKKWobojIFYqNRd0JQ3Q==
"@ensdomains/ens-avatar@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@ensdomains/ens-avatar/-/ens-avatar-1.0.0.tgz#731b02477f88c0abc3e2132465f1c4a427682bd2"
integrity sha512-coz6kMnQJAHxWTQ/fLGxYiJy8m5xURxMndrKKfTHZDw7rlSoVjXYywAhrasr3Vu8e2IqeLjSGVAb5KZArN7chQ==
dependencies:
"@ethersproject/contracts" "^5.7.0"
"@ethersproject/providers" "^5.7.0"
Expand Down

0 comments on commit f039865

Please sign in to comment.