Skip to content

Dev #76

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 20, 2025
Merged

Dev #76

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## CHANGELOG

### [25.6.0] - Mar 20, 2025
- Added support for `-allowjs` which allows dynamic JavaScript in HTML outputs and JinjaFx Input modals - this should only be enabled in internal environments where you trust your users
- Added support for a `script` option for JinjaFx Input modals to allow dynamic input modals - requires `-allowjs`

### [25.5.5] - Mar 17, 2025
- Update font look on MacOS to make it less heavy
- Added support for `-nocache` argument for internal development
Expand Down Expand Up @@ -423,6 +427,7 @@
### 21.11.0 - Nov 29, 2021
- Initial release

[25.6.0]: https://github.com/cmason3/jinjafx_server/compare/25.5.5...25.6.0
[25.5.5]: https://github.com/cmason3/jinjafx_server/compare/25.5.4...25.5.5
[25.5.4]: https://github.com/cmason3/jinjafx_server/compare/25.5.3...25.5.4
[25.5.3]: https://github.com/cmason3/jinjafx_server/compare/25.5.2...25.5.3
Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Once JinjaFx Server has been started with the `-s` argument then point your web
jinjafx_server -s [-l <address>] [-p <port>]
[-r <directory> | -s3 <aws s3 url> | -github <owner>/<repo>[:<branch>]]
[-rl <rate/limit>] [-tl <time limit>] [-ml <memory limit>]
[-logfile <logfile>] [-weblog] [-pandoc] [-v]
[-logfile <logfile>] [-weblog] [-pandoc] [-allowjs] [-nocache] [-v]

-s - start the JinjaFx Server
-l <address> - specify a listen address (default is '127.0.0.1')
Expand All @@ -34,6 +34,8 @@ Once JinjaFx Server has been started with the `-s` argument then point your web
-logfile <logfile> - specify a logfile for persistent logging
-weblog - enable web log interface (/logs)
-pandoc - enable support for DOCX using pandoc (requires pandoc)
-allowjs - allows javascript in `jinjafx_input` and html output
-nocache - disables versioned urls for internal development
-v - log all HTTP requests

Environment Variables:
Expand Down Expand Up @@ -79,6 +81,8 @@ The `-rl` argument is used to provide an optional rate limit of the source IP -

The `-weblog` argument in combination with the `JFX_WEBLOG_KEY` environment variable enables the Web Log interface to view the current application logs - this can be accessed from a web browser using the URL `/logs` - the user will be prompted for the key or they can provide it via a query string of `?key=<JFX_WEBLOG_KEY>`.

If you specify `-allowjs` then this allows you to inject dynamic JavaScript into HTML outputs and JinjaFx Input modals, but this basically disables the Content Security Policy, which protects you from XSS attacks. This is only advisable if you are hosting this internally and you trust your users.

### Shortcut Keys

As well as supporting the standard CodeMirror shortcut keys for the "data.csv", "global.yml", "vars.yml" and "template.j2" panes, it also supports the following custom shortcut keys:
Expand Down Expand Up @@ -181,6 +185,16 @@ jinjafx_input:
</div>
```

If you pass `-allowjs` on the command line then you can also specify a `script` section, which allows you to perform dynamic actions within your modal, e.g:

```yaml
jinjafx_input:
script: |2
document.getElementById('select_dropdown').addEventListener('change', function() {
// Do Something
});
```

You can also specify an optional `size` attribute alongside the `body` attribute which sets the width of the modal using the pre-defined Bootstrap sizes (i.e. "sm", "lg" and "xl"). The input form supports full native HTML validation using `required` and `pattern` attributes. The values which are input are then mapped to Jinja2 variables using the `data-var` custom attribute (e.g. `data-var="name"` would map to `jinjafx_input['name']` or `jinjafx_input.name`):

```jinja2
Expand Down
12 changes: 10 additions & 2 deletions jinjafx_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import re, argparse, hashlib, traceback, glob, hmac, uuid, struct, binascii, gzip, requests, ctypes, subprocess
import cmarkgfm, emoji

__version__ = '25.5.5'
__version__ = '25.6.0'

llock = threading.RLock()
rlock = threading.RLock()
Expand Down Expand Up @@ -387,9 +387,14 @@ def sanitise_dt(dt):
else:
r = [ 'text/plain', 404, '404 Not Found\r\n'.encode('utf-8'), sys._getframe().f_lineno ]

script_src = "'self' https://cdnjs.cloudflare.com"

if allowjs:
script_src += " 'unsafe-inline'"

headers = {
'X-Content-Type-Options': 'nosniff',
'Content-Security-Policy': "default-src 'self'; style-src 'self' https://cdnjs.cloudflare.com 'unsafe-inline'; script-src 'self' https://cdnjs.cloudflare.com; img-src data: *; frame-ancestors 'none'",
'Content-Security-Policy': "default-src 'self'; style-src 'self' https://cdnjs.cloudflare.com 'unsafe-inline'; script-src " + script_src + "; img-src data: *; frame-ancestors 'none'",
'Referrer-Policy': 'strict-origin-when-cross-origin'
}
etag = '"' + hashlib.sha224(repr(headers).encode('utf-8') + b'|' + r[0].encode('utf-8') + b'; ' + r[2]).hexdigest() + '"'
Expand Down Expand Up @@ -1122,6 +1127,7 @@ def main(rflag=[0]):
global rl_limit
global timelimit
global logfile
global allowjs
global nocache
global verbose
global pandoc
Expand All @@ -1145,9 +1151,11 @@ def main(rflag=[0]):
parser.add_argument('-logfile', metavar='<logfile>', type=str)
parser.add_argument('-weblog', action='store_true', default=False)
parser.add_argument('-pandoc', action='store_true', default=False)
parser.add_argument('-allowjs', action='store_true', default=False)
parser.add_argument('-nocache', action='store_true', default=False)
parser.add_argument('-v', action='store_true', default=False)
args = parser.parse_args()
allowjs = args.allowjs
nocache = args.nocache
verbose = args.v

Expand Down
2 changes: 1 addition & 1 deletion www/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/4.1.0/js-yaml.min.js" integrity="sha512-CSBhVREyzHAjAFfBlIBakjoRUKp5h7VSweP0InR/pAJyptH7peuhCsqAI/snV+TwZmXZqoUklpXp6R6wMnYf5Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.13/dayjs.min.js" integrity="sha512-FwNWaxyfy2XlEINoSnZh1JQ5TRRtGow0D6XcmAWmYCRgvqOUTnzCxPc9uF35u5ZEpirk1uhlPVA19tflhvnW1g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.13/plugin/relativeTime.min.js" integrity="sha512-MVzDPmm7QZ8PhEiqJXKz/zw2HJuv61waxb8XXuZMMs9b+an3LoqOqhOEt5Nq3LY1e4Ipbbd/e+AWgERdHlVgaA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="/97b58eeb/jinjafx_m.js"></script>
<script src="/a6880d00/jinjafx_m.js"></script>
</head>
<body>
<div id="overlay"></div>
Expand Down
15 changes: 15 additions & 0 deletions www/jinjafx_m.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ function getStatusText(code) {
var dt_epassword = null;
var delete_pending = false;
var input_form = null;
var input_script = null;
var r_input_form = null;
var jinput = null;
var protect_action = 0;
Expand Down Expand Up @@ -596,6 +597,13 @@ function getStatusText(code) {
}

if (vars['jinjafx_input'].hasOwnProperty('body')) {
if (vars['jinjafx_input'].hasOwnProperty('script')) {
if (input_script !== vars['jinjafx_input']['script']) {
input_script = vars['jinjafx_input']['script'];
input_form = null;
}
}

if (input_form !== vars['jinjafx_input']['body']) {
var xHR = new XMLHttpRequest();
xHR.open("POST", '/jinjafx?dt=jinjafx_input', true);
Expand All @@ -610,6 +618,13 @@ function getStatusText(code) {
r_input_form = d(obj.outputs['Output:text']);
document.getElementById('jinjafx_input_form').innerHTML = r_input_form;
input_form = vars['jinjafx_input']['body'];

if (vars['jinjafx_input'].hasOwnProperty('script')) {
var script = document.createElement('script');
script.innerHTML = vars['jinjafx_input']['script'];
document.getElementById('jinjafx_input').appendChild(script);
}

jinput = new bootstrap.Modal(document.getElementById('jinjafx_input'), {
keyboard: false
});
Expand Down