Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
supun-io committed Oct 23, 2024
1 parent 45e6862 commit badaba8
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 33 deletions.
22 changes: 22 additions & 0 deletions .temp/iframe-inner.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<body>
<script src="/website/static/child.js"></script>
<style>
#wrap {
background-color: blue;
width: 700px;
height: 50px;
}
</style>
<div id="wrap"></div>

<script>
const wrap = document.querySelector("#wrap");
wrap.onclick = function() {
wrap.style.height = wrap.style.height === "100px" ? "200px" : "100px";
}

function addElement() {
//
}
</script>
</body>
9 changes: 7 additions & 2 deletions src/Embed/Embed.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Hyvor\Unfold\Embed;

use Hyvor\Unfold\Embed\Iframe\PrivacyIframe;
use Hyvor\Unfold\Exception\EmbedUnableToResolveException;
use Hyvor\Unfold\Exception\EmbedParserException;
use Hyvor\Unfold\Exception\UnfoldException;
Expand All @@ -19,11 +20,11 @@ public static function getParsers(): array
$namespace = __NAMESPACE__ . '\\Platforms\\';

$parsers = array_map(
fn ($file) => $namespace . pathinfo((string)$file, PATHINFO_FILENAME),
fn($file) => $namespace . pathinfo((string)$file, PATHINFO_FILENAME),
(array)glob(__DIR__ . '/Platforms/*.php')
);

usort($parsers, fn ($a, $b) => $b::PRIORITY <=> $a::PRIORITY);
usort($parsers, fn($a, $b) => $b::PRIORITY <=> $a::PRIORITY);

return $parsers;
}
Expand Down Expand Up @@ -73,6 +74,10 @@ public static function getUnfoldedObject(
): Unfolded {
$oembed = self::parse($url, $context->config);

if ($context->config->embedIframeEndpoint && $oembed->html) {

Check failure on line 77 in src/Embed/Embed.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Access to an undefined property Hyvor\Unfold\UnfoldConfig::$embedIframeEndpoint.
$oembed->html = PrivacyIframe::wrap($oembed->html);
}

return Unfolded::fromEmbed(
$oembed,
$url,
Expand Down
21 changes: 21 additions & 0 deletions src/Embed/Iframe/PrivacyIframe.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,25 @@
class PrivacyIframe
{

public static function wrap(string $html): string
{
$encoded = base64_encode($html);

return <<<HTML
<iframe src="/endpoint?data=$encoded"/>
<iframe src="/media/embed?url=$url" />

Check failure on line 15 in src/Embed/Iframe/PrivacyIframe.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Undefined variable: $url
HTML;
}

}

class EmbedController
{
public function handle()

Check failure on line 23 in src/Embed/Iframe/PrivacyIframe.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Method Hyvor\Unfold\Embed\Iframe\EmbedController::handle() has no return type specified.
{
$url = $_GET['url'];
$embed = Unfold::unfold($url, EMBED);

Check failure on line 26 in src/Embed/Iframe/PrivacyIframe.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Call to static method unfold() on an unknown class Hyvor\Unfold\Embed\Iframe\Unfold.

Check failure on line 26 in src/Embed/Iframe/PrivacyIframe.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Constant EMBED not found.
echo $embed;
}
}
25 changes: 0 additions & 25 deletions src/UnfoldConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,6 @@ public function __construct(
*/
public UnfoldMethod $method = UnfoldMethod::LINK,

/**
* Adding embed codes directly to the page can be a privacy concern since
* it gives third-party platforms full access to the page via Javascript.
* The best solution is to wrap the embed code in an iframe.
*
* We tried using iframe `srcdoc` directly, but it resulted in many inconsistencies and issues
* with different platforms (ex: Reddit does not support about: scheme in srcdoc).
*
* So, the best solution is to use an iframe endpoint that wraps the embed code.
* This requires you to add an endpoint to your app to serve the iframe.
* Then, set that endpoint's absolute URL in this config.
* See https://unfold.hyvor.com/iframe for more details.
*
* Ex: 'https://yourapp.com/unfold-iframe'
*
* If this option is set to a string, the embed code will be wrapped in an iframe.
* It also comes with JS code to handle iframe resizing.
*/
public ?string $embedIframeEndpoint = null,

/**
* If the $method is UnfoldMethod::EMBED or UnfoldMethod::EMBED_LINK,
* and if we cannot find a way to embed the URL using our default parsers,
Expand Down Expand Up @@ -80,11 +60,6 @@ public function __construct(
*/
public string $httpUserAgent = 'Hyvor Unfold PHP Client',

/**
* TODO: Implement this
*/
public ?string $iframeEndpoint = null,

/**
* Meta requires an access_token to access the OEmbed Read Graph API
* This is required for both FacebookPost & Instagram
Expand Down
57 changes: 57 additions & 0 deletions website/src/routes/[[slug]]/Iframe.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<script>
import { Callout, CodeBlock } from '@hyvor/design/components';
</script>

<h1>Privacy Iframe</h1>

<p>
Adding embed codes directly to your website is a <strong>privacy concern</strong> since most of
the time they include Javascript libraries that can access your page and user's data. Using an
<strong>iframe to wrap the embed code</strong> is the best way to prevent this.
</p>

<h2 id="docker">Docker Image</h2>

<p>
If you are using the <a href="/docker">Docker image</a>, the iframe endpoint is already included.
On your website, use iframes with `src` set to <code>/iframe?url=my-url</code> to embed content.
</p>

<CodeBlock
code={`
<iframe src="https://unfold.example.org/iframe?url=https://url-to-embed.com"></iframe>
`}
/>

<h2 id="iframe-endpoint">PHP Library</h2>

<p>
If you are using the <a href="/php">PHP Library</a>, you have to set up an endpoint for the
iframe. Here is an example with Laravel:
</p>

<CodeBlock
code={`
use Hyvor\\Unfold\\Unfold;
use Hyvor\\Unfold\\Exceptions\\UnfoldException;
use Illuminate\\Http\\Request;
class IframeController
{
public function getIframe(Request $request)
{
$url = $request->input('url');
try {
$data = Unfold::unfold($url);
return PrivacyIframe::inner($data);
} catch (UnfoldException) {
// handle the exception
}
}
}
`}
language="js"
/>
2 changes: 1 addition & 1 deletion website/src/routes/[[slug]]/Introduction.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { CodeBlock } from '@hyvor/design/components';
</script>

<h1>Introduction</h1>
<h1>Hyvor Unfold</h1>

<p>
Hyvor Unfold is an open-source API that can fetch metadata from URLs for <strong
Expand Down
14 changes: 9 additions & 5 deletions website/src/routes/[[slug]]/docs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { ComponentType } from "svelte";
import Introduction from "./Introduction.svelte";
import Iframe from "./Iframe.svelte";

export const categories = [
export const categories: Category[] = [
{
name: 'Unfold',
pages: [
Expand All @@ -12,19 +13,22 @@ export const categories = [
},
{
name: 'PHP Library',
slug: 'php'
slug: 'php',
component: Introduction
},
{
name: 'Privacy Iframe',
slug: 'privacy-iframe'
slug: 'iframe',
component: Iframe
},
{
name: 'Docker Hosting',
slug: 'docker'
slug: 'docker',
component: Introduction
}
]
}
] as Category[];
];

export const pages = categories.reduce((acc, category) => acc.concat(category.pages), [] as Page[]);

Expand Down
8 changes: 8 additions & 0 deletions website/src/routes/iframe-test/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<p>This is an iframe that changes its height every time you click on it.</p>

<iframe src="http://localhost:1234/.temp/iframe-inner.html" style="margin:30px;" width="700"
></iframe>

<svelte:head>
<script src="/parent.js"></script>
</svelte:head>
25 changes: 25 additions & 0 deletions website/src/routes/iframe-test/inner/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script lang="ts">
import { onMount } from 'svelte';
let items = 1;
function handleClick() {
items += 1;
}
</script>

<svelte:head>
<script src="/child.js"></script>
</svelte:head>

<body on:click={handleClick}>
{#each Array(items) as _, i}
<div style="height:150px" />
{/each}
</body>

<style>
body {
background-color: blue;
}
</style>
42 changes: 42 additions & 0 deletions website/static/child.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
(function () {
function sendHeight() {
const height = document.documentElement.scrollHeight;

try {
const iframe = window.frameElement;
if (iframe) {
iframe.style.height = `${height}px`;
} else {
throw new Error('iframe not found');
}
} catch (e) {
window.parent.postMessage(
{
type: 'unfold-iframe-resize',
height
},
'*'
);
}
}

let mutationCallTimeout = null;

function processMutations() {
if (mutationCallTimeout) {
clearTimeout(mutationCallTimeout);
}
mutationCallTimeout = setTimeout(sendHeight, 100);
}

function init() {
const mutation = new window.MutationObserver(processMutations);
mutation.observe(document.body, {
childList: true,
subtree: true
});
sendHeight();
}

document.addEventListener('DOMContentLoaded', init);
})();
15 changes: 15 additions & 0 deletions website/static/parent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
(function () {
window.addEventListener('message', function (event) {
const source = event.source;
const iframes = document.querySelectorAll('iframe');

for (let iframe in iframes) {
if (iframes[iframe].contentWindow === source) {
console.log('found the source', event.data);
if (event.data.type === 'unfold-iframe-resize') {
iframes[iframe].style.height = `${event.data.height}px`;
}
}
}
});
})();

0 comments on commit badaba8

Please sign in to comment.