Skip to content

Instantly share code, notes, and snippets.

@rhee-elten
Last active August 4, 2023 01:46
Show Gist options
  • Save rhee-elten/b4c1b3c9892500a0c2e0884f11965e1d to your computer and use it in GitHub Desktop.
Save rhee-elten/b4c1b3c9892500a0c2e0884f11965e1d to your computer and use it in GitHub Desktop.
[WIP] gitea renderer - jupyter notebook using nb.js (TBD frame security check workaround) /////////////////////////////
#!/bin/bash
mkdir -p "${GITEA_CUSTOM}/tmp/render-notebook"
exec 2>> "${GITEA_CUSTOM}/tmp/render-notebook/trace.txt"
## DEBUG: echo params & envs
## PARAMS:
echo "=== Script: $(dirname $0)" 1>&2
echo "=== Date: $(date +'%Y-%m-%d %H:%M:%S')" 1>&2
echo "=== Args:" "$@" 1>&2
echo "=== Env:" 1>&2
env 1>&2
t_start=$(date +%s)
notebook_url="data:text/html;base64,$(/bin/base64 -w 0 -)"
t_elapsed=$(expr $(date +%s) - $t_start)
echo "Encoded bytes: ${#notebook_url}, elapsed: ${t_elapsed} seconds" 1>&2
## =========================================================
## README
## =========================================================
<<EEE
[[custom modifications required]]
config/app.ini:
===============
[cors]
# ENABLED: false: enable cors headers (disabled by default)
# SCHEME: http: scheme of allowed requests
# ALLOW_DOMAIN: *: list of requesting domains that are allowed
# ALLOW_SUBDOMAIN: false: allow subdomains of headers listed above to request
# METHODS: GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS: list of methods allowed to request
# MAX_AGE: 10m: max time to cache response
# ALLOW_CREDENTIALS: false: allow request with credentials
# HEADERS: Content-Type,User-Agent: additional headers that are permitted in requests
# X_FRAME_OPTIONS: SAMEORIGIN: Set the X-Frame-Options header value.
ENABLED = true
ALLOW_DOMAIN = *
ALLOW_CREDENTIALS = true
# [markup.jupyter]
# ENABLED = true
# FILE_EXTENSIONS = .ipynb
# RENDER_COMMAND = "jupyter nbconvert --stdin --stdout --to html --template basic"
# IS_INPUT_FILE = false
[markup.jupyter]
ENABLED = true
FILE_EXTENSIONS = .ipynb
RENDER_COMMAND = "/data/gitea/public/app/render-notebook/script/render-notebook"
IS_INPUT_FILE = false
RENDER_CONTENT_MODE = iframe
[markup.sanitizer.jupyter.img]
ALLOW_DATA_URI_IMAGES = true
custom/header.tmpl:
===================
<!--
<style type="text/css">
.markup.jupyter iframe {
height:900px!important;
overflow:scroll!important;
}
</style>
-->
custom/footer.tmpl:
===================
<!--
<script>
(function(){
const iframe = document.getElementsByName("giteaExternalRender")[0];
const src = iframe.src;
iframe.sandbox.add("allow-scripts")
iframe.sandbox.add("allow-same-origin")
//iframe.setAttribute("src","about:blank")
iframe.contentWindow.addEventListener("load",function(){
this.height=giteaExternalRender.document.documentElement.scrollHeight
})
iframe.setAttribute("src",src)
})()
</script>
-->
<script>
// Function to resize the iframe based on the received height message
function resizeIframe(event) {
const iframe = document.querySelector("div.markup.jupyter iframe");
if (iframe) {
iframe.style.height = event.data + "px";
}
}
// Listen for the 'message' event and call resizeIframe function
window.addEventListener("message", resizeIframe);
</script>
base/head.tmpl
==============
head.tmpl 에서 referrer 에 no-referrer 대신 same-origin 이나 strict-origin-when-cross-origin 추가 고려:
<meta name="referrer" content="no-referrer"> <!-- content="strict-origin-when-cross-origin"> -->
renderer.go (?)
===============
<iframe ... onload="this.height=haha.document.documentElement.scrollHeight" sandbox="allow-scripts">
처럼 onload 와 sandbox=allow-scripts 를 함께 사용시 onload 에서 cross-origin frame 예외 발생
gitea cheatsheet 중에서 다음 문장 검토
RENDER_CONTENT_MODE: sanitized How the content will be rendered.
* sanitized: Sanitize the content and render it inside current page,
default to only allow a few HTML tags and attributes. Customized
sanitizer rules can be defined in [markup.sanitizer.*].
* no-sanitizer: Disable the sanitizer and render the content inside
current page. It's insecure and may lead to XSS attack if the
content contains malicious code.
* iframe: Render the content in a separate standalone page and
embed it into current page by iframe.
***The iframe is in sandbox mode with same-origin disabled,
and the JS code are safely isolated from parent page.***
==> sandbox="allow-scripts allow-same-origin" 으로 수정 필요
EEE
## =========================================================
## HTML template
## =========================================================
cat <<EEE
<!-- <h1>BEGIN Rendered Notebook</h1> -->
<div id="nbjs-nb-$$">
<!--Inserts Notebook HTML here-->
</div>
<!-- <script src="/assets/js/nb.js"></script> -->
<!-- <script src="http://192.168.1.146:3000/assets/js/nb.js"></script> -->
<script src="https://cdn.jsdelivr.net/gh/psthomas/notebook-html/nb.min.js"></script>
<!--highlight.js-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.12.0/build/styles/default.min.css">
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.12.0/build/highlight.min.js"></script>
<!--showdown.js-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.8.6/showdown.min.js"></script>
<script>
const url="$notebook_url";
const id="user-content-nbjs-nb-$$";
//Create converter object and modify some settings
const converter = new showdown.Converter();
converter.setOption('headerLevelStart', 2); //Maximum header is <h2>
converter.setFlavor('github'); //Use Github flavored markdown
nb.insertNotebook(url, id, {
"code": true, //Include code cells
"markdown": true, //Include markdown cells
"tables": true, //Include html data tables
"images": true, //Include .png outputs
"headline": false, //Include the first <h*> headline, removing is useful if page has title already
"tableoutline": false, //Removes the black table outline
"codehighlighter": "highlightjs", //No code highlighting. Options: "none", "highlightjs", "prettyprint"
"mdconverter": converter //Use included simple markdown converter. Options: "default", showdown object
});
// Wait for the iframe content to load and then send the height to the parent page
window.addEventListener("load", function(){
const height = document.body.scrollHeight;
parent.postMessage(height, "*");
});
</script>
<!-- <h1>END Rendered Notebook</h1> -->
EEE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment