From b4c319585e39806c9542d6b8abe6b85c41de674a Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Sun, 4 Sep 2022 11:06:19 +0300 Subject: [PATCH] cleanup + file store path sanitization... Signed-off-by: Alex A. Naanou --- pwiki/page.js | 20 -------------------- pwiki/path.js | 16 ++++++++++++++++ pwiki/store/base.js | 33 ++++++++++++++++++++------------- pwiki/store/file.js | 9 ++++++--- pwiki2.js | 3 ++- 5 files changed, 44 insertions(+), 37 deletions(-) diff --git a/pwiki/page.js b/pwiki/page.js index 2b21065..f57400d 100755 --- a/pwiki/page.js +++ b/pwiki/page.js @@ -44,7 +44,6 @@ function(name){ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// XXX PATH_VARS // XXX FUNC need to handle functions in store... var BasePage = module.BasePage = @@ -88,7 +87,6 @@ object.Constructor('BasePage', { // other places path variables can be resolved: // - navigation (below) // - macro expansion... - // XXX EXPERIMENTAL... path_vars: { NOW: function(){ return Date.timeStamp() }, @@ -607,7 +605,6 @@ function(spec, func){ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// XXX PATH_VARS need to handle path variables... // XXX filters (and macros?) should be features for simpler plugin handlng (???) // XXX STUB filters... // XXX rename to pWikiPage??? @@ -1552,23 +1549,6 @@ object.Constructor('CachedPage', Page, { return getCachedProp(this, 'text') }, set text(value){ return setCachedProp(this, 'text', value) }, - - - /*/ XXX PREVIEW EXPERIMENTAL... - // ...this can be usefull for partial rendering and then on the - // js level filling in the details... - __preview_size__: 100, - get preview(){ - var text = this.text - if(text instanceof Promise){ - text.then(function(text){ - this.onPreviewReady() }) - // return a placeholder for the upcoming data... - return '...' } - return text.slice(0, this.__preview_size__ || 100) }, - onPreviewReady: types.event.Event('onPreviewReady'), - //*/ - }) diff --git a/pwiki/path.js b/pwiki/path.js index 65991b3..fb5d376 100755 --- a/pwiki/path.js +++ b/pwiki/path.js @@ -129,6 +129,22 @@ module = { : path.join('/')) : path }, //*/ + sanitize: function(path, format='auto'){ + format = format == 'auto' ? + (path instanceof Array ? + 'array' + : 'string') + : format + path = this.split(path) + ;(path[0] == '' + || path[0] == '.' + || path[0] == '..') + && path.shift() + path.at(-1) == '' + && path.pop() + return format == 'string' ? + path.join('/') + : path }, split: function(path){ return this.normalize(path, 'array') }, join: function(...parts){ diff --git a/pwiki/store/base.js b/pwiki/store/base.js index fe3d439..afc0e58 100755 --- a/pwiki/store/base.js +++ b/pwiki/store/base.js @@ -137,7 +137,7 @@ function(name, get, update, ...args){ var BaseStore = module.BaseStore = { - // XXX NEXT revise naming... + // XXX revise naming... next: undefined, // NOTE: .data is not part of the spec and can be implementation-specific, @@ -236,24 +236,35 @@ module.BaseStore = { return path in this.data && path }, exists: async function(path){ + // XXX SANITIZE... + path = pwpath.sanitize(path, 'string') + /*/ path = pwpath.normalize(path, 'string') + //*/ return (await this.__exists__(path)) // NOTE: all paths at this point and in store are // absolute, so we check both with the leading // '/' and without it to make things a bit more // relaxed and return the actual matching path... + // XXX SANITIZE... + || (await this.__exists__('/'+ path)) + /*/ || (await this.__exists__( path[0] == '/' ? path.slice(1) : ('/'+ path))) - // XXX NEXT + //*/ // delegate to .next... || ((this.next || {}).__exists__ && (await this.next.__exists__(path) + // XXX SANITIZE... + || await this.next.__exists__('/'+path))) + /*/ || await this.next.__exists__( path[0] == '/' ? path.slice(1) : ('/'+ path)))) + //*/ // normalize the output... || false }, // find the closest existing alternative path... @@ -405,6 +416,9 @@ module.BaseStore = { /* XXX ENERGETIC... path = await this.resolve(path, strict) /*/ + // XXX SANITIZE... + path = pwpath.sanitize(path, 'string') + //*/ path = path.includes('*') && (energetic == true ? await this.find(path) @@ -420,7 +434,6 @@ module.BaseStore = { // and returning a a/b which can be undefined... return that.get(p, strict) }) : (await this.__get__(path) - // XXX NEXT ?? ((this.next || {}).__get__ && this.next.get(path, strict))) }, @@ -473,7 +486,11 @@ module.BaseStore = { return this } var exists = await this.exists(path) path = exists + // XXX SANITIZE... + || pwpath.sanitize(path, 'string') + /*/ || pwpath.normalize(path, 'string') + //*/ data = data instanceof Promise ? await data : data @@ -568,16 +585,6 @@ module.BaseStore = { && typeof(res) != 'string') ? JSON.stringify(res, options.replacer, options.space) : res }, - - /*/ XXX NEXT EXPERIMENTAL... - nest: function(base){ - return { - __proto__: base - ?? BaseStore, - next: this, - data: {} - } }, - //*/ } diff --git a/pwiki/store/file.js b/pwiki/store/file.js index 72f9061..99ea300 100755 --- a/pwiki/store/file.js +++ b/pwiki/store/file.js @@ -80,6 +80,7 @@ async function(base, sub, options){ base = null } var {index} = getOpts(options) + sub = pwpath.sanitize(sub) var target = encode( base ? pwpath.join(base, sub) @@ -99,6 +100,7 @@ async function(base, sub, options){ base = null } var {index} = getOpts(options) + sub = pwpath.sanitize(sub) var target = encode( base ? pwpath.join(base, sub) @@ -124,6 +126,7 @@ async function(base, sub, options){ base = null } var {index, verbose} = getOpts(options) + sub = pwpath.sanitize(sub) var levels = pwpath.split(sub) for(var level of levels){ base = encode( @@ -147,7 +150,6 @@ async function(base, sub, options){ await fs.promises.mkdir(base, {recursive: true}) await fs.promises.rename(base +'.pwiki-bak', base +'/'+ index) } return base } -// XXX metadata??? var update = module.update = async function(base, sub, data, options){ @@ -158,6 +160,7 @@ async function(base, sub, data, options){ base = null } var {index} = getOpts(options) + sub = pwpath.sanitize(sub) var target = encode( base ? pwpath.join(base, sub) @@ -196,6 +199,7 @@ async function(base, sub, options){ base = '' } var {index} = getOpts(options) + sub = pwpath.sanitize(sub) // remove leaf... var target = encode( base == '' ? @@ -264,8 +268,7 @@ async function(base, options){ await fs.promises.rename(path +'/'+ index, path+'.pwiki-bak') await fs.promises.rmdir(path) await fs.promises.rename(path +'.pwiki-bak', path) - continue } - } } }) } + continue } } } }) } // XXX backup metadata... // - date diff --git a/pwiki2.js b/pwiki2.js index 7f178e3..0c1e4a3 100755 --- a/pwiki2.js +++ b/pwiki2.js @@ -28,7 +28,7 @@ * example: * @include(./path ..) * -> -* XXX FILE prevent paths from using reserved chars like: ":", "#", ... +* XXX prevent paths from using reserved chars like: ":", "#", ... * XXX OPTIMIZE CACHE match pattern paths -- to catch page creation... * 1) explicit subpath matching -- same as .match(..) * 2) identify recursive patterns -- same as ** @@ -165,6 +165,7 @@ * XXX DEPENDS/CACHE @macro(..) introduces a dependency on count (pattern) * ...not sure how we track these... * XXX revise how we handle .strict mode in page's .raw and .text... +* XXX NEXT might be a good idea to add an API to restore page(s) from .next... * * *