Access to a the templating context object in global functions #327

Closed
peleteiro opened this Issue Nov 25, 2014 · 13 comments

Comments

Projects
None yet
8 participants
@peleteiro

Just like #109, It would be quite useful to have access to the render context object inside global functions.

A use case:

I have a CMS system and I need a function which returns the url for content. The code bellow should work, as it works if it were a filter.

env.addGlobal("urlFor", function (content) {
    return this.ctx.baseUrl + "/" + content.slug;
});

Thanks

@garygreen

This comment has been minimized.

Show comment
Hide comment
@garygreen

garygreen Nov 25, 2014

Member

That would be pretty cool, to be honest I didn't really think about that when I added addGlobal. I'll look into it

Member

garygreen commented Nov 25, 2014

That would be pretty cool, to be honest I didn't really think about that when I added addGlobal. I'll look into it

@nelsonpecora

This comment has been minimized.

Show comment
Hide comment
@nelsonpecora

nelsonpecora Jan 15, 2015

This would also be helpful just in templates themselves. If my context is { 'some-random-property': {} } I'd like to grab the whole context object and do stuff with it (looping, Object.keys(), etc). Is this possible at all?

This would also be helpful just in templates themselves. If my context is { 'some-random-property': {} } I'd like to grab the whole context object and do stuff with it (looping, Object.keys(), etc). Is this possible at all?

@ArmorDarks

This comment has been minimized.

Show comment
Hide comment
@ArmorDarks

ArmorDarks Apr 13, 2015

Would be great feature 👍

Would be great feature 👍

@devoidfury

This comment has been minimized.

Show comment
Hide comment
@devoidfury

devoidfury Apr 13, 2015

Contributor

In the meantime, you can work around some of it.

var nunjucks = require('nunjucks');
var env = new nunjucks.Environment();
nunjucks._globals = require('nunjucks/src/globals.js');

// give access to globals through a global
nunjucks._globals.globals = function() { return nunjucks._globals }


env.addFilter('setSelf', function() { 
    var self = this;
    this.ctx.self = function() { return self }
})
env.addFilter('json', JSON.stringify)

env.addGlobal('test', 'hello')
env.addGlobal('another', 'world')
env.addGlobal('helper', function(self) { 
    console.log('context inside helper. foo: ' + self().ctx.foo) 
})

console.log(env.renderString(
    '\n\nThis is a test! See globals:\n' +
    '{{ globals()|json(null, 2) }}' + // json-prints the globals object
    '{{ $|setSelf }}' + // adds a function to the context that exposes the context
    '{{ helper(self) }}', // pass ctx getter to helper
    {foo: 'bar'}
));
Contributor

devoidfury commented Apr 13, 2015

In the meantime, you can work around some of it.

var nunjucks = require('nunjucks');
var env = new nunjucks.Environment();
nunjucks._globals = require('nunjucks/src/globals.js');

// give access to globals through a global
nunjucks._globals.globals = function() { return nunjucks._globals }


env.addFilter('setSelf', function() { 
    var self = this;
    this.ctx.self = function() { return self }
})
env.addFilter('json', JSON.stringify)

env.addGlobal('test', 'hello')
env.addGlobal('another', 'world')
env.addGlobal('helper', function(self) { 
    console.log('context inside helper. foo: ' + self().ctx.foo) 
})

console.log(env.renderString(
    '\n\nThis is a test! See globals:\n' +
    '{{ globals()|json(null, 2) }}' + // json-prints the globals object
    '{{ $|setSelf }}' + // adds a function to the context that exposes the context
    '{{ helper(self) }}', // pass ctx getter to helper
    {foo: 'bar'}
));
@nelsonpecora

This comment has been minimized.

Show comment
Hide comment
@nelsonpecora

nelsonpecora Apr 13, 2015

Yup, I also worked around this with a filter, but it's a little hacky.

env.addFilter('getContext', function () {
  return this.ctx;
}

You have to pass something into the filter, which confuses other devs:

{% set foo = ""|getContext %}
{{ foo }}

Yup, I also worked around this with a filter, but it's a little hacky.

env.addFilter('getContext', function () {
  return this.ctx;
}

You have to pass something into the filter, which confuses other devs:

{% set foo = ""|getContext %}
{{ foo }}
@ArmorDarks

This comment has been minimized.

Show comment
Hide comment
@ArmorDarks

ArmorDarks May 31, 2015

Thanks for sharing those workaround. @devoidfury is quite tricky one :)

Is there any chances to see native support?

Thanks in advance!

Thanks for sharing those workaround. @devoidfury is quite tricky one :)

Is there any chances to see native support?

Thanks in advance!

@ArmorDarks ArmorDarks referenced this issue Jun 6, 2015

Closed

Nunjucks 2.0 #347

@jlongster jlongster closed this in 97d9fe4 Jun 12, 2015

@jlongster

This comment has been minimized.

Show comment
Hide comment
@jlongster

jlongster Jun 12, 2015

Member

This wasn't too hard, sorry it took so long!

Member

jlongster commented Jun 12, 2015

This wasn't too hard, sorry it took so long!

@ArmorDarks

This comment has been minimized.

Show comment
Hide comment
@ArmorDarks

ArmorDarks Jun 12, 2015

Nice! Thanks a lot!

Nice! Thanks a lot!

@valtido

This comment has been minimized.

Show comment
Hide comment
@valtido

valtido Aug 4, 2016

@nelsonpecora Isn't this really dangerous security wise?

return this.ctx; would it not also return the settings? as in this.ctx.settings? or in template {{ getContext .settings }}

Which in turn has access to the following JSON.stringify object:

"{"x-powered-by":true,"etag":"weak","env":"development","query parser":"extended","subdomain offset":2,"trust proxy":false,"views":"...\\views","jsonp callback name":"callback","view engine":"njk"}"

Also not to mention if anything else is exposed to the context in the future.

I wonder why settings has been put on the ctx in the first place?

Any advise?

valtido commented Aug 4, 2016

@nelsonpecora Isn't this really dangerous security wise?

return this.ctx; would it not also return the settings? as in this.ctx.settings? or in template {{ getContext .settings }}

Which in turn has access to the following JSON.stringify object:

"{"x-powered-by":true,"etag":"weak","env":"development","query parser":"extended","subdomain offset":2,"trust proxy":false,"views":"...\\views","jsonp callback name":"callback","view engine":"njk"}"

Also not to mention if anything else is exposed to the context in the future.

I wonder why settings has been put on the ctx in the first place?

Any advise?

@nelsonpecora

This comment has been minimized.

Show comment
Hide comment
@nelsonpecora

nelsonpecora Aug 4, 2016

Hmm! Good point. The native implementation should probably strip that stuff out

Hmm! Good point. The native implementation should probably strip that stuff out

@carljm

This comment has been minimized.

Show comment
Hide comment
@carljm

carljm Aug 4, 2016

Member

In general, nunjucks doesn't intend to support untrusted template authors. There are too many ways for a malicious template author to at the very least DoS the system.

That said, I'm not sure either why settings are stored on the context. Convenience maybe?

Member

carljm commented Aug 4, 2016

In general, nunjucks doesn't intend to support untrusted template authors. There are too many ways for a malicious template author to at the very least DoS the system.

That said, I'm not sure either why settings are stored on the context. Convenience maybe?

@ArmorDarks

This comment has been minimized.

Show comment
Hide comment
@ArmorDarks

ArmorDarks Aug 4, 2016

So far I don't see how those settings could be used in malefic way. Any examples?

So far I don't see how those settings could be used in malefic way. Any examples?

@valtido

This comment has been minimized.

Show comment
Hide comment
@valtido

valtido Aug 5, 2016

here is what the object looks like,


env                 :"development"
etag                :"weak"
etag fn             :wetag(body, encoding)
jsonp callback name :"callback"
query parser        :"extended"
query parser fn     :parseExtendedQueryString(str)
subdomain offset    :2
trust proxy         :false
trust proxy fn      :trustNone()
view                :NunjucksView(name, opts)
view engine         :"njk"
views               :"C:\Users\..\dev\views"
x-powered-by        :true

I was more focused, on the view method, they can serve a different view with a bit of hacking.

but what's to say you leave that on, forget all about it, and one day nunjucks, decides to extend the settings object to include more sensitive information, the context should display the settings period (as a principal).

I mean security wise, you do not want to expose anything you have explicitly decide to do so.

valtido commented Aug 5, 2016

here is what the object looks like,


env                 :"development"
etag                :"weak"
etag fn             :wetag(body, encoding)
jsonp callback name :"callback"
query parser        :"extended"
query parser fn     :parseExtendedQueryString(str)
subdomain offset    :2
trust proxy         :false
trust proxy fn      :trustNone()
view                :NunjucksView(name, opts)
view engine         :"njk"
views               :"C:\Users\..\dev\views"
x-powered-by        :true

I was more focused, on the view method, they can serve a different view with a bit of hacking.

but what's to say you leave that on, forget all about it, and one day nunjucks, decides to extend the settings object to include more sensitive information, the context should display the settings period (as a principal).

I mean security wise, you do not want to expose anything you have explicitly decide to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment