@rhinostone/swig-core 2.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/backend.js +718 -0
- package/lib/cache.js +75 -0
- package/lib/dateformatter.js +201 -0
- package/lib/engine.js +414 -0
- package/lib/filters.js +43 -0
- package/lib/index.js +21 -0
- package/lib/ir.js +873 -0
- package/lib/loaders/filesystem.js +59 -0
- package/lib/loaders/index.js +53 -0
- package/lib/loaders/memory.js +63 -0
- package/lib/security.js +25 -0
- package/lib/tokenparser.js +920 -0
- package/lib/tokentypes.js +78 -0
- package/lib/utils.js +184 -0
- package/package.json +26 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
var fs = require('fs'),
|
|
2
|
+
path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Loads templates from the file system.
|
|
6
|
+
* @alias swig.loaders.fs
|
|
7
|
+
* @example
|
|
8
|
+
* swig.setDefaults({ loader: swig.loaders.fs() });
|
|
9
|
+
* @example
|
|
10
|
+
* // Load Templates from a specific directory (does not require using relative paths in your templates)
|
|
11
|
+
* swig.setDefaults({ loader: swig.loaders.fs(__dirname + '/templates' )});
|
|
12
|
+
* @param {string} [basepath=''] Path to the templates as string. Assigning this value allows you to use semi-absolute paths to templates instead of relative paths.
|
|
13
|
+
* @param {string} [encoding='utf8'] Template encoding
|
|
14
|
+
*/
|
|
15
|
+
module.exports = function (basepath, encoding) {
|
|
16
|
+
var ret = {};
|
|
17
|
+
|
|
18
|
+
encoding = encoding || 'utf8';
|
|
19
|
+
basepath = (basepath) ? path.normalize(basepath) : null;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Resolves <var>to</var> to an absolute path or unique identifier. This is used for building correct, normalized, and absolute paths to a given template.
|
|
23
|
+
* @alias resolve
|
|
24
|
+
* @param {string} to Non-absolute identifier or pathname to a file.
|
|
25
|
+
* @param {string} [from] If given, should attempt to find the <var>to</var> path in relation to this given, known path.
|
|
26
|
+
* @return {string}
|
|
27
|
+
*/
|
|
28
|
+
ret.resolve = function (to, from) {
|
|
29
|
+
if (basepath) {
|
|
30
|
+
from = basepath;
|
|
31
|
+
} else {
|
|
32
|
+
from = (from) ? path.dirname(from) : process.cwd();
|
|
33
|
+
}
|
|
34
|
+
return path.resolve(from, to);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Loads a single template. Given a unique <var>identifier</var> found by the <var>resolve</var> method this should return the given template.
|
|
39
|
+
* @alias load
|
|
40
|
+
* @param {string} identifier Unique identifier of a template (possibly an absolute path).
|
|
41
|
+
* @param {function} [cb] Asynchronous callback function. If not provided, this method should run synchronously.
|
|
42
|
+
* @return {string} Template source string.
|
|
43
|
+
*/
|
|
44
|
+
ret.load = function (identifier, cb) {
|
|
45
|
+
if (!fs || (cb && !fs.readFile) || !fs.readFileSync) {
|
|
46
|
+
throw new Error('Unable to find file ' + identifier + ' because there is no filesystem to read from.');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
identifier = ret.resolve(identifier);
|
|
50
|
+
|
|
51
|
+
if (cb) {
|
|
52
|
+
fs.readFile(identifier, encoding, cb);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
return fs.readFileSync(identifier, encoding);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return ret;
|
|
59
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @namespace TemplateLoader
|
|
3
|
+
* @description Swig is able to accept custom template loaders written by you, so that your templates can come from your favorite storage medium without needing to be part of the core library.
|
|
4
|
+
* A template loader consists of two methods: <var>resolve</var> and <var>load</var>. Each method is used internally by Swig to find and load the source of the template before attempting to parse and compile it.
|
|
5
|
+
* @example
|
|
6
|
+
* // A theoretical memcached loader
|
|
7
|
+
* var path = require('path'),
|
|
8
|
+
* Memcached = require('memcached');
|
|
9
|
+
* function memcachedLoader(locations, options) {
|
|
10
|
+
* var memcached = new Memcached(locations, options);
|
|
11
|
+
* return {
|
|
12
|
+
* resolve: function (to, from) {
|
|
13
|
+
* return path.resolve(from, to);
|
|
14
|
+
* },
|
|
15
|
+
* load: function (identifier, cb) {
|
|
16
|
+
* memcached.get(identifier, function (err, data) {
|
|
17
|
+
* // if (!data) { load from filesystem; }
|
|
18
|
+
* cb(err, data);
|
|
19
|
+
* });
|
|
20
|
+
* }
|
|
21
|
+
* };
|
|
22
|
+
* };
|
|
23
|
+
* // Tell swig about the loader:
|
|
24
|
+
* swig.setDefaults({ loader: memcachedLoader(['localhost:11211']) });
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @function
|
|
29
|
+
* @name resolve
|
|
30
|
+
* @memberof TemplateLoader
|
|
31
|
+
* @description
|
|
32
|
+
* Resolves <var>to</var> to an absolute path or unique identifier. This is used for building correct, normalized, and absolute paths to a given template.
|
|
33
|
+
* @param {string} to Non-absolute identifier or pathname to a file.
|
|
34
|
+
* @param {string} [from] If given, should attempt to find the <var>to</var> path in relation to this given, known path.
|
|
35
|
+
* @return {string}
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @function
|
|
40
|
+
* @name load
|
|
41
|
+
* @memberof TemplateLoader
|
|
42
|
+
* @description
|
|
43
|
+
* Loads a single template. Given a unique <var>identifier</var> found by the <var>resolve</var> method this should return the given template.
|
|
44
|
+
* @param {string} identifier Unique identifier of a template (possibly an absolute path).
|
|
45
|
+
* @param {function} [cb] Asynchronous callback function. If not provided, this method should run synchronously.
|
|
46
|
+
* @return {string} Template source string.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @private
|
|
51
|
+
*/
|
|
52
|
+
exports.fs = require('./filesystem');
|
|
53
|
+
exports.memory = require('./memory');
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
var path = require('path'),
|
|
2
|
+
utils = require('../utils');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Loads templates from a provided object mapping.
|
|
6
|
+
* @alias swig.loaders.memory
|
|
7
|
+
* @example
|
|
8
|
+
* var templates = {
|
|
9
|
+
* "layout": "{% block content %}{% endblock %}",
|
|
10
|
+
* "home.html": "{% extends 'layout.html' %}{% block content %}...{% endblock %}"
|
|
11
|
+
* };
|
|
12
|
+
* swig.setDefaults({ loader: swig.loaders.memory(templates) });
|
|
13
|
+
*
|
|
14
|
+
* @param {object} mapping Hash object with template paths as keys and template sources as values.
|
|
15
|
+
* @param {string} [basepath] Path to the templates as string. Assigning this value allows you to use semi-absolute paths to templates instead of relative paths.
|
|
16
|
+
*/
|
|
17
|
+
module.exports = function (mapping, basepath) {
|
|
18
|
+
var ret = {};
|
|
19
|
+
|
|
20
|
+
basepath = (basepath) ? path.normalize(basepath) : null;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Resolves <var>to</var> to an absolute path or unique identifier. This is used for building correct, normalized, and absolute paths to a given template.
|
|
24
|
+
* @alias resolve
|
|
25
|
+
* @param {string} to Non-absolute identifier or pathname to a file.
|
|
26
|
+
* @param {string} [from] If given, should attempt to find the <var>to</var> path in relation to this given, known path.
|
|
27
|
+
* @return {string}
|
|
28
|
+
*/
|
|
29
|
+
ret.resolve = function (to, from) {
|
|
30
|
+
if (basepath) {
|
|
31
|
+
from = basepath;
|
|
32
|
+
} else {
|
|
33
|
+
from = (from) ? path.dirname(from) : '/';
|
|
34
|
+
}
|
|
35
|
+
return path.resolve(from, to);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Loads a single template. Given a unique <var>identifier</var> found by the <var>resolve</var> method this should return the given template.
|
|
40
|
+
* @alias load
|
|
41
|
+
* @param {string} identifier Unique identifier of a template (possibly an absolute path).
|
|
42
|
+
* @param {function} [cb] Asynchronous callback function. If not provided, this method should run synchronously.
|
|
43
|
+
* @return {string} Template source string.
|
|
44
|
+
*/
|
|
45
|
+
ret.load = function (pathname, cb) {
|
|
46
|
+
var src, paths;
|
|
47
|
+
|
|
48
|
+
paths = [pathname, pathname.replace(/^(\/|\\)/, '')];
|
|
49
|
+
|
|
50
|
+
src = mapping[paths[0]] || mapping[paths[1]];
|
|
51
|
+
if (!src) {
|
|
52
|
+
utils.throwError('Unable to find template "' + pathname + '".');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (cb) {
|
|
56
|
+
cb(null, src);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
return src;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return ret;
|
|
63
|
+
};
|
package/lib/security.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template-source property access blocklist for CVE-2023-25345.
|
|
3
|
+
*
|
|
4
|
+
* Any identifier that matches this list is rejected at parse time by
|
|
5
|
+
* parser.js, tags/set.js, tags/for.js, tags/macro.js, and tags/import.js.
|
|
6
|
+
* The list covers read access (`{{ __proto__ }}` / `{{ foo.__proto__ }}`
|
|
7
|
+
* / `{{ foo["__proto__"] }}`), write access (`{% set __proto__ = ... %}`
|
|
8
|
+
* / `{% set foo["__proto__"] = ... %}`), loop variables
|
|
9
|
+
* (`{% for __proto__ in items %}`), macro names (`{% macro __proto__() %}`),
|
|
10
|
+
* and import aliases (`{% import "f" as __proto__ %}`).
|
|
11
|
+
*
|
|
12
|
+
* Kept as a shared constant so any future tag that assigns to `_ctx.*`
|
|
13
|
+
* or otherwise exposes an identifier as a property key picks up the
|
|
14
|
+
* full blocklist without drift across copies.
|
|
15
|
+
*
|
|
16
|
+
* See .claude/security.md for the full attack-vector table and the
|
|
17
|
+
* tags/parser checkpoints that consume this list.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Property names that must never reach `_ctx.<name>` or be accessed
|
|
22
|
+
* via dot / string-bracket notation from template source.
|
|
23
|
+
* @type {string[]}
|
|
24
|
+
*/
|
|
25
|
+
exports.dangerousProps = ['__proto__', 'constructor', 'prototype'];
|