gina 0.3.7-alpha.9 → 0.3.8
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/CHANGELOG.md +14 -0
- package/ROADMAP.md +4 -3
- package/framework/v0.3.8/VERSION +1 -0
- package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/csrf/src/main.js +176 -18
- package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/session/src/main.js +14 -2
- package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/conf/settings.json +16 -9
- package/framework/{v0.3.7-alpha.9 → v0.3.8}/package.json +1 -1
- package/gna.js +4 -4
- package/llms.txt +12 -0
- package/package.json +5 -3
- package/script/post_install.js +40 -6
- package/script/pre_install.js +36 -5
- package/framework/v0.3.7-alpha.9/VERSION +0 -1
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/AUTHORS +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/LICENSE +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/html/nolayout.html +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/html/static.html +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/img/android-chrome-192x192.png +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/img/android-chrome-512x512.png +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/img/apple-touch-icon.png +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/img/favicon-16x16.png +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/img/favicon-32x32.png +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/img/favicon.ico +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/beemaster/beemaster.css +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/beemaster/beemaster.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/beemaster/index.html +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/css/gina.min.css +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/css/gina.min.css.br +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/css/gina.min.css.gz +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/html/statusbar.html +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/html/statusbar.html.br +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/html/statusbar.html.gz +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/inspector/have_heart_one-webfont.woff2 +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/inspector/index.html +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/inspector/inspector.css +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/inspector/inspector.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/inspector/logo.svg +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/js/gina.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/js/gina.min.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/js/gina.min.js.br +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/js/gina.min.js.gz +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js.br +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js.gz +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/config.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/ai/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/ai/lib/connector.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/couchbase/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/couchbase/lib/connector.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/couchbase/lib/connector.v2.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/couchbase/lib/connector.v3.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/couchbase/lib/connector.v4.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/couchbase/lib/n1ql.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/couchbase/lib/session-store.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/couchbase/lib/session-store.v2.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/couchbase/lib/session-store.v3.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/couchbase/lib/session-store.v4.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/mysql/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/mysql/lib/connector.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/postgresql/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/postgresql/lib/connector.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/redis/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/redis/lib/session-store.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/sql-parser.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/sqlite/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/sqlite/lib/connector.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/connectors/sqlite/lib/session-store.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/content.encoding +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/controller/controller.framework.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/controller/controller.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/controller/controller.render-json.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/controller/controller.render-nunjucks.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/controller/controller.render-stream.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/controller/controller.render-swig.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/controller/controller.render-v1.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/controller/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/deps/busboy-1.6.0/LICENSE +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/deps/busboy-1.6.0/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/deps/busboy-1.6.0/lib/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/deps/busboy-1.6.0/lib/types/multipart.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/deps/busboy-1.6.0/lib/types/urlencoded.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/deps/busboy-1.6.0/lib/utils.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/deps/busboy-1.6.0/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/deps/streamsearch-1.1.0/LICENSE +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/deps/streamsearch-1.1.0/lib/sbmh.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/deps/streamsearch-1.1.0/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/dev/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/dev/lib/class.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/dev/lib/factory.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/dev/lib/tools.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/gna.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/locales/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/locales/currency.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/locales/dist/language/en.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/locales/dist/language/fr.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/locales/dist/region/en.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/locales/dist/region/fr.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/locales/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/mime.types +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/model/entity.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/model/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/model/template/entityFactory.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/model/template/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/csrf/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/csrf/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/file/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/file/build.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/file/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/intl/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/intl/build.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/intl/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/intl/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/session/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/session/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/storage/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/storage/build.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/storage/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/storage/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/validator/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/validator/build.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/validator/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/validator/src/form-validator.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/plugins/lib/validator/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/router.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/server.express.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/server.isaac.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/server.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/status.codes +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/_gitignore +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle/config/app.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle/config/connectors.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle/config/routing.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle/config/settings.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle/config/settings.server.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle/config/templates.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle/config/watchers.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle/controllers/controller.content.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle/controllers/controller.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle/controllers/setup.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_namespace/controllers/controller.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_public/css/default.css +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_public/css/home.css +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_public/css/vendor/readme.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_public/favicon.ico +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_public/js/vendor/readme.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_public/readme.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_templates/handlers/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_templates/html/content/homepage.html +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_templates/html/includes/error-msg-noscript.html +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_templates/html/includes/error-msg-outdated-browser.html +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/boilerplate/bundle_templates/html/layouts/main.html +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/command/gina.bat.tpl +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/command/gina.tpl +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/conf/env.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/conf/manifest.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/conf/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/conf/statics.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/conf/templates.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/error/client/json/401.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/error/client/json/403.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/error/client/json/404.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/error/server/html/50x.html +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/error/server/json/500.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/error/server/json/503.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/core/template/extensions/logger/config.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/console.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/context.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/data/LICENSE +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/data/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/data/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/data/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/dateFormat.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/json/LICENSE +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/json/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/json/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/json/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/path.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/plugins/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/plugins/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/plugins/src/api-error.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/plugins/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/prototypes.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/task.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/helpers/text.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/archiver/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/archiver/build.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/archiver/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/archiver/src/dep/jszip.min.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/archiver/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/async/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/async/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cache/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cache/build.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cache/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cache/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/aliases.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/add.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/arguments.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/build.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/copy.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/cp.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/help.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/help.txt +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/list.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/mcp-start.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/mcp.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/oas.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/openapi.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/remove.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/rename.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/restart.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/rm.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/start.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/status.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/bundle/stop.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/cache/stats.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/connector/add.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/connector/arguments.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/connector/help.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/connector/help.txt +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/connector/list.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/connector/migrate.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/connector/remove.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/connector/rm.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/env/add.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/env/get.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/env/help.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/env/help.txt +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/env/link-dev.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/env/list.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/env/remove.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/env/rm.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/env/set.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/env/unset.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/env/use.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/arguments.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/build.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/dot.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/get.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/help.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/help.txt +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/init.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/link-node-modules.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/link.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/msg.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/open.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/restart.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/set.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/start.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/status.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/stop.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/tail.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/update.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/framework/version.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/gina-dev.1.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/gina-framework.1.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/gina.1.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/helper.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/inspector/help.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/inspector/help.txt +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/inspector/open.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/minion/help.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/minion/help.txt +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/msg.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/port/help.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/port/help.txt +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/port/inc/scan.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/port/list.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/port/reset.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/port/set.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/add.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/arguments.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/build.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/help.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/help.txt +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/import.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/list.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/move.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/remove.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/rename.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/restart.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/rm.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/start.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/status.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/project/stop.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/protocol/help.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/protocol/help.txt +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/protocol/list.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/protocol/set.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/scope/add.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/scope/help.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/scope/help.txt +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/scope/link-local.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/scope/link-production.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/scope/list.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/scope/remove.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/scope/rm.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/scope/use.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/service/help.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/service/help.txt +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/service/list.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cmd/view/add.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/collection/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/collection/build.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/collection/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/collection/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/config.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/connector-registry/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/connector-registry/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cron/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cron/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/cron/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/domain/LICENSE +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/domain/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/domain/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/domain/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/generator/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/inherits/LICENSE +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/inherits/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/inherits/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/inherits/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/inspector-redact/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/inspector-redact/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/logger/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/logger/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/logger/src/containers/default/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/logger/src/containers/file/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/logger/src/containers/file/lib/logrotator/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/logger/src/containers/file/lib/logrotator/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/logger/src/containers/mq/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/logger/src/containers/mq/listener.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/logger/src/containers/mq/speaker.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/logger/src/helper.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/logger/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/math/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/mcp-dispatch/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/mcp-dispatch/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/mcp-http/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/mcp-http/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/mcp-server/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/mcp-server/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/merge/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/merge/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/merge/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/model.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/nunjucks-filters/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/nunjucks-filters/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/nunjucks-filters/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/nunjucks-resolver/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/nunjucks-resolver/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/proc.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/routing/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/routing/build.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/routing/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/routing/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/routing/src/radix.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/routing-introspect/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/routing-introspect/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/session-store.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/shell.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/state.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/swig-filters/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/swig-filters/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/swig-filters/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/swig-resolver/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/swig-resolver/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/url/README.md +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/url/index.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/url/routing.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/uuid/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/uuid/src/main.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/validator.js +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/watcher/package.json +0 -0
- /package/framework/{v0.3.7-alpha.9 → v0.3.8}/lib/watcher/src/main.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,20 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
|
|
6
6
|
and is generated by [Changie](https://github.com/miniscruff/changie).
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
## 0.3.8 - 2026-04-26
|
|
10
|
+
### Fixed
|
|
11
|
+
* Fixed `npm install -g gina` failing with `Cannot find module 'psl'` on fresh and upgrade installs (regression from 0.3.7). The pre/post-install scripts no longer load the framework `lib` registry — `psl` and `@rhinostone/swig` are now declared as top-level npm dependencies so the runtime resolves them via the standard module resolution chain, and a helpers pre-load in the install scripts ensures `lib/logger`'s circular load completes correctly so internal helpers' module-local `console` references bind to the full Logger singleton.
|
|
12
|
+
|
|
13
|
+
## 0.3.7 - 2026-04-26
|
|
14
|
+
### Added
|
|
15
|
+
* Released `0.3.7` — cumulative stable of the `0.3.7-alpha.1` through `0.3.7-alpha.10` cycle. Headline tracks: **Web Security CSRF trilogy** (`gina.plugins.Session()` cookie hardening + `gina.plugins.Csrf()` signed double-submit token middleware + Origin/Referer pre-filter; OWASP ASVS 4.0 V4.2.1 aligned; opt-in plugin shape; per-route `csrfExempt: true` for webhook receivers). **Nunjucks template engine opt-in** (`render.engine = "nunjucks"` per bundle; filter parity #NJ1, setResources/asset injection #NJ2, render cache #NJ3, Early Hints 103 auto-send #NJ4). **MCP server** (`bundle:mcp` static manifest emit + `bundle:mcp-start` stdio and HTTP transports; #AI8 Phases 1/2a/2b). **Connector CLI** (`connector:list/add/rm/migrate`; #CN10). **Eval-safety hardening** (#SCS1 family — collection safe-evaluator + validator-plugin grammar-locked walker replacements; vendored-dep CVE-visibility invariant locked in via OSV scan workflow). Supply-chain trim (`psl` swap for vendored MPL-2.0 PSL data, `optimist` removal). Release-pipeline hardening (`gna.js` stable-version sync at framework-dir rename, StateStore + gina.db sync across renames, asset-plugin build honours `--gzip-bin`/`--brotli-bin` overrides). Plus `Session.name` drop-in identity restoration in alpha.10. See per-alpha sections for per-feature detail and test counts; full suite 3822/3822 at the stable cut.
|
|
16
|
+
|
|
17
|
+
## 0.3.7-alpha.10 - 2026-04-26 (npm only — no git tag)
|
|
18
|
+
### Fixed
|
|
19
|
+
* `gina.plugins.Session()` no longer clobbers the wrapper's `Function.name` property. Bundles that introspect the wrapper (`require('gina').plugins.Session(require('express-session')).name`) now see `'session'` (matching upstream) instead of `'ginaSession'`. Achieved via a small refactor: the outer wrapper delegates to an inner `ginaSessionDispatch` named function, with `Object.defineProperty(wrapped, 'name', { value: expressSession.name, configurable: true })` overriding the outer `.name`. The inner `ginaSessionDispatch` frame stays visible in stack traces, so gina remains detectable for debugging while the public-facing identity is the upstream's. Static-surface preservation (`Store`, `MemoryStore`, `Session`, `Cookie`) and the SameSite=None invariant are unchanged. 2 new unit tests in `test/core/session-plugin.test.js` (drop-in identity assertion + stack-trace visibility lock). Full suite 3768/3768 (3766 baseline + 2 new). Surfaced from a freelancer/v3 session: "Gina's wrapper clobbering expressSession.name — is an upstream concern".
|
|
20
|
+
### Security
|
|
21
|
+
* `gina.plugins.Csrf()` now layers an Origin/Referer pre-filter ON TOP of the signed double-submit token verify (`#CSRF3`). On every mutating request (POST/PUT/PATCH/DELETE) the middleware reads `Origin` first, falls back to parsing the host out of `Referer` when `Origin` is absent (or is the literal `"null"` sentinel browsers send for sandboxed iframes), and matches the result against `settings.json > csrf.allowedOrigins`. Both headers missing → 403 `[csrf] forbidden — missing origin/referer`. Mismatch → 403 `[csrf] forbidden — origin not allowed`. The token verify only runs after the Origin check passes, so a forged token + matching cookie still gets rejected when the request didn't come from an allowed origin (token layer ≠ Origin layer). Per-route `csrfExempt: true` bypasses BOTH layers consistently. New `settings.json` key `csrf.allowedOrigins`: empty/unset defaults to `[bundleHostname]` (auto-derived from `conf[bundle][env].hostname` or composed from `server.scheme + host + server.port`); non-empty replaces the default with an explicit allowlist for multi-domain bundles. Entries are matched literally case-insensitive after parsing down to `scheme://host[:port]` — different scheme on the same host doesn't match (`http://example.com` ≠ `https://example.com`); different port doesn't match. Factory throws at startup when `csrf.allowedOrigins` is empty AND no bundle hostname can be resolved — error message points at both fixes. 54 new unit tests (parser helpers, allowlist precedence, behavioural matrix Origin × Referer × allowlist, scheme/port discrimination, `Origin: "null"` sentinel handling, negative-invariant lock that matching token + mismatching Origin still 403s, exempt interaction, source-inspection guards pinning the pre-filter ordering); full suite 3822/3822 (prior 3768 + 54). Closes the three-phase CSRF trilogy started by `#CSRF1` (cookie hardening, alpha.8) and `#CSRF2` (signed double-submit token, alpha.9).
|
|
22
|
+
|
|
9
23
|
## 0.3.7-alpha.9 - 2026-04-26 (npm only — no git tag)
|
|
10
24
|
### Added
|
|
11
25
|
* Exposed gina.csrfToken and gina.csrfInput in swig template context (#CSRF2 follow-up). When a bundle has registered the Csrf plugin and req.csrfToken is set on the active request, controller.js > setOptions() now publishes two keys to the template data: gina.csrfToken (raw base64url string) and gina.csrfInput (pre-formatted <input type="hidden" name="<fieldName>" value="<token>"> HTML). Templates render the hidden input with either {{ gina.csrfInput | safe }} or the manual <input ... value="{{ gina.csrfToken }}"> form. The field name comes from settings.json > csrf.fieldName (default _csrf, matching the plugin) and is HTML-attribute-escaped defensively (& " < >) before interpolation. The token itself is base64url ([A-Za-z0-9_-]) by construction so it is interpolated verbatim — encoding it would break round-trip when the form is submitted. When req.csrfToken is absent (bundle has not adopted the plugin) neither key is set; templates can guard with {% if gina.csrfToken %}. 25 unit tests in test/core/controller-csrf-context.test.js cover the source-inspection guards, the missing/empty/non-string rejection, the configured-fieldName path, the four HTML-attribute escapes, and the negative invariant (no eval, no template-literal interpolation, no encoding of the token).
|
package/ROADMAP.md
CHANGED
|
@@ -28,6 +28,7 @@ This roadmap covers planned features, architectural improvements, new connectors
|
|
|
28
28
|
| --- | --- | --- | --- |
|
|
29
29
|
| ✅ | **Automatic version migration** — Upgrading or downgrading gina (e.g. `0.1.x → 0.2.0`, `0.5.x → 1.0.0`) automatically migrates `~/.gina/` config to the new version on first startup. Downgrade is free — old version data is never removed. | `0.1.8` | 2026-03-26 |
|
|
30
30
|
| ✅ | **`watchers.json`** — First-class bundle config for file watchers. Declare watchers on config files with event-based notification (no polling). Foundation for the dev-mode hot-reload system. | `0.2.0` | 2026-03-29 |
|
|
31
|
+
| 📋 | **i18n core** — Per-bundle message catalogs under `bundle/locales/<culture>.json` with a fallback chain (specific culture → base language → default). Server-side `t(key, [params], [culture])` global helper with parameter interpolation and CLDR pluralisation. Swig and Nunjucks filters with the same surface (`{{ "key"\|t }}`, `{{ "key"\|t({ name: x }) }}`). Per-request locale negotiation from URL prefix / cookie / `Accept-Language` / settings default. CLI: `gina i18n:scan` for missing-key coverage per culture, `i18n:add <culture>` to seed a new catalog, `i18n:export` / `i18n:import` for `.po` / `.csv` / `.json` round-trip with translators. Headless by design — the visual translation editor lands later as the first content feature in Beemaster (admin Phase 3). | `0.3.8` | Q2 2026 |
|
|
31
32
|
| 📋 | **PWA scaffold** — `gina bundle:add` drops `manifest.json`, a service worker stub (`sw.js`), and the required `<meta>` / `<link>` tags into the bundle boilerplate. Zero runtime dependency. Enables Gina apps to be installed on mobile as PWAs without additional tooling. | `0.4.0` | Q4 2026 |
|
|
32
33
|
| ✅ | **Per-bundle framework version** — Declare `"gina_version": "0.1.8"` on any bundle entry in `manifest.json` to pin that bundle to a specific installed framework version. The socket server continues running its own version; only the spawned bundle process uses the declared version. Validated against the tracked version list in `main.json` before start. `--gina-version=X.Y.Z` flag on `bundle:start` provides the same override without touching config files. | `0.3.0` | 2026-03-31 |
|
|
33
34
|
| ✅ | **PATCH method** — `req.patch` populated with the parsed request body (JSON or form-encoded). `req.body` aliases `req.patch`. URI params merged. `"method": "PATCH"` valid in `routing.json`. Use PATCH for partial updates (only sent fields change) vs PUT which replaces the full resource. | `0.3.0` | 2026-03-31 |
|
|
@@ -137,13 +138,13 @@ Complete the removal of `eval` / `new Function` call sites from the published ta
|
|
|
137
138
|
|
|
138
139
|
## Web Security
|
|
139
140
|
|
|
140
|
-
Cross-site request forgery protection. Three-phase defense-in-depth plan aligned with OWASP ASVS 4.0 V4.2.1; each phase shippable on its own.
|
|
141
|
+
Cross-site request forgery protection. Three-phase defense-in-depth plan aligned with OWASP ASVS 4.0 V4.2.1; each phase shippable on its own. All three phases shipped: cookie hardening in `0.3.7-alpha.8`, signed double-submit token middleware in `0.3.7-alpha.9`, Origin/Referer pre-filter in `0.3.7-alpha.10`.
|
|
141
142
|
|
|
142
143
|
| Status | Feature | Version | Target |
|
|
143
144
|
| --- | --- | --- | --- |
|
|
144
145
|
| ✅ | **Cookie hardening (baseline)** — Opt-in plugin `gina.plugins.Session` wraps `express-session` and injects `SameSite=Lax` + `HttpOnly` + `Secure=auto` defaults from `settings.json > session.cookie.{sameSite,httpOnly,secure}` into the cookie options before the middleware sees them. Bundle-supplied cookie options always win, so intentional configuration is preserved. Adoption is a one-line swap in the bundle bootstrap: `var session = require('gina').plugins.Session(require('express-session'))`. Browser-parity invariant enforced at factory call time: `SameSite=None` without `Secure` throws at bundle startup. Migration guide flags cross-site cookie-send bundles (rare — third-party OAuth embeds, iframe flows) that must set `sameSite: "none"` + `secure: true` explicitly. 41 unit tests (source-inspection guards + mergeCookie + invariant negative-lock + resolveSettingsDefaults + end-to-end through stub express-session + registration + template integrity). | `0.3.7-alpha.8` | 2026-04-24 |
|
|
145
146
|
| ✅ | **Signed double-submit token middleware** — Stateless signed-double-submit-cookie pattern (OWASP ASVS 4.0 V4.2.1). Opt-in plugin `gina.plugins.Csrf()`: HMAC-SHA256 cookie bound to session ID + matching `X-Gina-CSRF-Token` header (or `_csrf` form field) required on POST/PUT/PATCH/DELETE; `timingSafeEqual` comparison; safe methods (GET/HEAD/OPTIONS) pass through. Per-route opt-out via `routing.json > "csrfExempt": true` for webhook receivers (Stripe, GitHub, etc.). Server secret read from `process.env.GINA_CSRF_SECRET` at factory-call time — no dev fallback. Sessionless or session-after-csrf misorder produces a clear `next(err)` message pointing at the fix. Stateless so it scales with distributed Redis/K8s sessions without server-side storage; signed so sibling subdomains cannot inject cookies. 69 unit tests (source-inspection guards, generateToken/verifyToken primitives, negative-invariant lock, issue + verify middlewares, per-route exempt, plugin registration, settings template integrity). Validator AJAX header injection + controller template context (`{{ gina.csrfToken }}` / `{{ gina.csrfInput \| safe }}`) ship in follow-up commits. | `0.3.7-alpha.9` | 2026-04-25 |
|
|
146
|
-
|
|
|
147
|
+
| ✅ | **Origin/Referer pre-filter** — Secondary check on mutating methods, layered on top of the token middleware INSIDE `gina.plugins.Csrf()`: parses `Origin` first, falls back to the host portion of `Referer`, and matches against `settings.json > csrf.allowedOrigins`. Both headers missing → 403 `missing origin/referer`. Mismatch → 403 `origin not allowed`. Empty/unset `allowedOrigins` defaults to `[bundleHostname]` (auto-derived from `conf[bundle][env].hostname` or composed from `server.scheme + host + server.port`); non-empty = explicit allowlist for multi-domain bundles. Per-route `csrfExempt: true` bypasses BOTH Origin and token layers consistently. Negative-invariant lock: matching token + mismatching Origin still 403s — token layer ≠ Origin layer. Factory throws at startup when neither a settings allowlist nor a bundle hostname can be resolved. 54 unit tests added (parseRequestOrigin/parseOriginString helpers, resolveBundleHostname, resolveAllowedOrigins precedence, behavioural matrix Origin × Referer × allowlist, scheme/port discrimination, `Origin: "null"` sentinel handling, negative-invariant lock, exempt interaction, source-inspection guards pinning the pre-filter ordering). Full suite 3822/3822 (prior 3768 + 54). | `0.3.7-alpha.10` | 2026-04-26 |
|
|
147
148
|
|
|
148
149
|
---
|
|
149
150
|
|
|
@@ -286,7 +287,7 @@ Windows compatibility is a hard requirement for `1.0.0`. The alpha scope covers
|
|
|
286
287
|
|
|
287
288
|
## Inspector
|
|
288
289
|
|
|
289
|
-
Gina's built-in per-bundle inspector. Phases 1–2 ship as an embedded SPA at `/_gina/inspector/` inside every bundle's own HTTP server (dev mode). Phase 3 evolves it into a standalone web app served by `services/src/inspector/` that can connect to any bundle in any environment — including production. Beemaster (global admin app) is a separate project.
|
|
290
|
+
Gina's built-in per-bundle inspector. Phases 1–2 ship as an embedded SPA at `/_gina/inspector/` inside every bundle's own HTTP server (dev mode). Phase 3 evolves it into a standalone web app served by `services/src/inspector/` that can connect to any bundle in any environment — including production. Beemaster (global admin app) is a separate project — also the planned home for content-management surfaces such as the **i18n translation editor** (the visual layer of i18n core).
|
|
290
291
|
|
|
291
292
|
**Why a standalone web app:** Electron is heavy and adds distribution burden. A browser extension is browser-specific and can't inspect from a different machine. The standalone web app works locally and remotely, any browser, zero install. A browser extension companion can be layered on top later.
|
|
292
293
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.3.8
|
|
@@ -8,25 +8,33 @@
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Csrf plugin (#CSRF2) — signed double-submit token middleware
|
|
11
|
+
* Csrf plugin (#CSRF2 / #CSRF3) — signed double-submit token middleware
|
|
12
|
+
* with an Origin/Referer pre-filter.
|
|
12
13
|
*
|
|
13
|
-
* Stateless CSRF defense aligned with OWASP ASVS 4.0 V4.2.1.
|
|
14
|
-
*
|
|
15
|
-
* value on mutating requests (POST/PUT/PATCH/DELETE). Token shape:
|
|
14
|
+
* Stateless CSRF defense aligned with OWASP ASVS 4.0 V4.2.1. On mutating
|
|
15
|
+
* methods (POST/PUT/PATCH/DELETE) the middleware now layers two checks:
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* 1. #CSRF3 — Origin/Referer pre-filter. Reads `Origin` first, falls
|
|
18
|
+
* back to parsing the host out of `Referer`. Both missing → 403.
|
|
19
|
+
* Mismatch against `csrf.allowedOrigins` → 403. Belt-and-suspenders
|
|
20
|
+
* that catches edge cases tokens might miss (referrer-header log
|
|
21
|
+
* leaks, legacy browser bugs, misconfigured reverse proxies).
|
|
22
|
+
* 2. #CSRF2 — signed double-submit token verify. Token shape:
|
|
19
23
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
24
|
+
* <nonce_b64url>.<mac_b64url>
|
|
25
|
+
* mac = HMAC-SHA256(sessionId + ':' + nonce_b64url, GINA_CSRF_SECRET)
|
|
26
|
+
*
|
|
27
|
+
* Safe methods (GET/HEAD/OPTIONS) issue a fresh token cookie and pass
|
|
28
|
+
* through. Per-route opt-out via `routing.json > "csrfExempt": true`
|
|
29
|
+
* bypasses both layers (consistent across token + Origin checks).
|
|
30
|
+
*
|
|
31
|
+
* Bundles adopt the plugin with two lines in their bootstrap, AFTER the
|
|
32
|
+
* session middleware:
|
|
22
33
|
*
|
|
23
34
|
* var csrf = require('gina').plugins.Csrf();
|
|
24
35
|
* app.use(session({...})); // must register session FIRST
|
|
25
36
|
* app.use(csrf);
|
|
26
37
|
*
|
|
27
|
-
* Per-route opt-out via `routing.json > "csrfExempt": true` for webhook
|
|
28
|
-
* receivers (Stripe, GitHub, etc.) where CSRF defense doesn't apply.
|
|
29
|
-
*
|
|
30
38
|
* @module plugins/csrf
|
|
31
39
|
*/
|
|
32
40
|
|
|
@@ -48,18 +56,20 @@ var MAC_BYTES = 32;
|
|
|
48
56
|
* the merged framework defaults.
|
|
49
57
|
*
|
|
50
58
|
* @returns {{cookieName: string, headerName: string, fieldName: string,
|
|
51
|
-
* rotate: string, safeMethods: string[]
|
|
59
|
+
* rotate: string, safeMethods: string[],
|
|
60
|
+
* allowedOrigins: string[]|null}}
|
|
52
61
|
* @throws {Error} when a setting has an unsupported value.
|
|
53
62
|
* @inner
|
|
54
63
|
* @private
|
|
55
64
|
*/
|
|
56
65
|
function resolveSettingsDefaults() {
|
|
57
66
|
var defaults = {
|
|
58
|
-
cookieName:
|
|
59
|
-
headerName:
|
|
60
|
-
fieldName:
|
|
61
|
-
rotate:
|
|
62
|
-
safeMethods:
|
|
67
|
+
cookieName: DEFAULT_COOKIE_NAME,
|
|
68
|
+
headerName: DEFAULT_HEADER_NAME,
|
|
69
|
+
fieldName: DEFAULT_FIELD_NAME,
|
|
70
|
+
rotate: DEFAULT_ROTATE,
|
|
71
|
+
safeMethods: DEFAULT_SAFE_METHODS.slice(),
|
|
72
|
+
allowedOrigins: null
|
|
63
73
|
};
|
|
64
74
|
var csrfConf = {};
|
|
65
75
|
|
|
@@ -101,10 +111,134 @@ function resolveSettingsDefaults() {
|
|
|
101
111
|
return String(m).toUpperCase();
|
|
102
112
|
});
|
|
103
113
|
}
|
|
114
|
+
if (Array.isArray(csrfConf.allowedOrigins)) {
|
|
115
|
+
defaults.allowedOrigins = csrfConf.allowedOrigins
|
|
116
|
+
.filter(function (o) { return typeof o === 'string' && o; })
|
|
117
|
+
.map(function (o) { return o.toLowerCase(); });
|
|
118
|
+
}
|
|
104
119
|
|
|
105
120
|
return defaults;
|
|
106
121
|
}
|
|
107
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Extract `scheme://host[:port]` from a URL-like string. Returns `null`
|
|
125
|
+
* for `"null"` (sandboxed-iframe sentinel), empty input, or anything
|
|
126
|
+
* that doesn't have a parseable scheme + authority.
|
|
127
|
+
*
|
|
128
|
+
* @param {string} s
|
|
129
|
+
* @returns {string|null}
|
|
130
|
+
* @inner
|
|
131
|
+
* @private
|
|
132
|
+
*/
|
|
133
|
+
function parseOriginString(s) {
|
|
134
|
+
if (typeof s !== 'string' || !s) return null;
|
|
135
|
+
if (s === 'null') return null; // browsers send literal "null" for sandboxed iframes
|
|
136
|
+
var m = /^([a-z][a-z0-9+.\-]*):\/\/([^\/?#]+)/i.exec(s);
|
|
137
|
+
if (!m) return null;
|
|
138
|
+
return (m[1] + '://' + m[2]).toLowerCase();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Best-effort detection of the origin a request was issued from. Reads
|
|
143
|
+
* `Origin` first; falls back to parsing the host out of `Referer` when
|
|
144
|
+
* `Origin` is missing (rare — some same-origin legacy browsers strip
|
|
145
|
+
* `Origin` on safe-then-mutating sequences).
|
|
146
|
+
*
|
|
147
|
+
* @param {object} req
|
|
148
|
+
* @returns {string|null} `"scheme://host[:port]"` or null
|
|
149
|
+
* @inner
|
|
150
|
+
* @private
|
|
151
|
+
*/
|
|
152
|
+
function parseRequestOrigin(req) {
|
|
153
|
+
if (!req || !req.headers) return null;
|
|
154
|
+
var origin = parseOriginString(req.headers.origin);
|
|
155
|
+
if (origin) return origin;
|
|
156
|
+
var referer = req.headers.referer || req.headers.referrer;
|
|
157
|
+
return parseOriginString(referer);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Resolve the bundle's configured origin from the active runtime
|
|
162
|
+
* configuration. Tries `conf[bundle][env].hostname` first (a full URL
|
|
163
|
+
* the framework resolves at startup), then composes one from
|
|
164
|
+
* `server.scheme + '://' + host + ':' + server.port`. Returns `null`
|
|
165
|
+
* when neither shape is present (e.g. test stub without a host).
|
|
166
|
+
*
|
|
167
|
+
* @returns {string|null}
|
|
168
|
+
* @inner
|
|
169
|
+
* @private
|
|
170
|
+
*/
|
|
171
|
+
function resolveBundleHostname() {
|
|
172
|
+
try {
|
|
173
|
+
var ctx = getContext();
|
|
174
|
+
var bundle = ctx && ctx.bundle;
|
|
175
|
+
var env = ctx && ctx.env;
|
|
176
|
+
var conf = (typeof getConfig === 'function') ? getConfig() : null;
|
|
177
|
+
if (!bundle || !env || !conf || !conf[bundle] || !conf[bundle][env]) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
var bc = conf[bundle][env];
|
|
181
|
+
if (typeof bc.hostname === 'string' && bc.hostname) {
|
|
182
|
+
return parseOriginString(bc.hostname) || bc.hostname.toLowerCase();
|
|
183
|
+
}
|
|
184
|
+
if (bc.server
|
|
185
|
+
&& typeof bc.server.scheme === 'string' && bc.server.scheme
|
|
186
|
+
&& typeof bc.host === 'string' && bc.host
|
|
187
|
+
&& (bc.server.port || bc.server.port === 0)) {
|
|
188
|
+
return (bc.server.scheme + '://' + bc.host + ':' + bc.server.port).toLowerCase();
|
|
189
|
+
}
|
|
190
|
+
} catch (ignored) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Compute the allowlist for the Origin pre-filter. Precedence:
|
|
198
|
+
* 1. `opts.allowedOrigins` (factory override, test harness)
|
|
199
|
+
* 2. `settings.json > csrf.allowedOrigins`
|
|
200
|
+
* 3. `[ resolveBundleHostname() ]` — the bundle's configured origin
|
|
201
|
+
*
|
|
202
|
+
* Returns an array of lowercase `scheme://host[:port]` strings. Throws
|
|
203
|
+
* at factory time when the resolved list ends up empty — that means
|
|
204
|
+
* neither the user nor the framework could supply a hostname, and
|
|
205
|
+
* letting the middleware run would 403 every mutating request.
|
|
206
|
+
*
|
|
207
|
+
* @param {string[]|null} fromOpts — `opts.allowedOrigins`
|
|
208
|
+
* @param {string[]|null} fromSettings — `settings.csrf.allowedOrigins`
|
|
209
|
+
* @returns {string[]}
|
|
210
|
+
* @throws {Error} when no origin can be resolved.
|
|
211
|
+
* @inner
|
|
212
|
+
* @private
|
|
213
|
+
*/
|
|
214
|
+
function resolveAllowedOrigins(fromOpts, fromSettings) {
|
|
215
|
+
var list = null;
|
|
216
|
+
if (Array.isArray(fromOpts) && fromOpts.length > 0) {
|
|
217
|
+
list = fromOpts;
|
|
218
|
+
} else if (Array.isArray(fromSettings) && fromSettings.length > 0) {
|
|
219
|
+
list = fromSettings;
|
|
220
|
+
} else {
|
|
221
|
+
var bundleHost = resolveBundleHostname();
|
|
222
|
+
list = bundleHost ? [bundleHost] : [];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
list = list
|
|
226
|
+
.filter(function (o) { return typeof o === 'string' && o; })
|
|
227
|
+
.map(function (o) {
|
|
228
|
+
var parsed = parseOriginString(o);
|
|
229
|
+
return parsed || o.toLowerCase();
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
if (list.length === 0) {
|
|
233
|
+
throw new Error(
|
|
234
|
+
'[gina csrf] csrf.allowedOrigins is empty and the bundle hostname could not be'
|
|
235
|
+
+ ' resolved from getConfig(). Set settings.json > csrf.allowedOrigins'
|
|
236
|
+
+ ' (e.g. ["https://example.com"]) or pass {allowedOrigins:[...]} to Csrf().'
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
return list;
|
|
240
|
+
}
|
|
241
|
+
|
|
108
242
|
/**
|
|
109
243
|
* 16 cryptographically secure random bytes.
|
|
110
244
|
*
|
|
@@ -313,8 +447,13 @@ var SESSIONLESS_MESSAGE =
|
|
|
313
447
|
* @param {string} [opts.fieldName]
|
|
314
448
|
* @param {string} [opts.rotate] — `"per-session"` (default) or `"per-request"`
|
|
315
449
|
* @param {string[]} [opts.safeMethods]
|
|
450
|
+
* @param {string[]} [opts.allowedOrigins] — #CSRF3 allowlist of origins that may
|
|
451
|
+
* issue mutating requests. Defaults to
|
|
452
|
+
* `settings.json > csrf.allowedOrigins`,
|
|
453
|
+
* which itself defaults to the bundle's
|
|
454
|
+
* configured hostname.
|
|
316
455
|
* @returns {function} — Express-compatible middleware `(req, res, next)`
|
|
317
|
-
* @throws {Error} when `GINA_CSRF_SECRET` is missing.
|
|
456
|
+
* @throws {Error} when `GINA_CSRF_SECRET` is missing or no origin can be resolved.
|
|
318
457
|
*/
|
|
319
458
|
function Csrf(opts) {
|
|
320
459
|
opts = opts || {};
|
|
@@ -346,6 +485,10 @@ function Csrf(opts) {
|
|
|
346
485
|
? opts.safeMethods.map(function (m) { return String(m).toUpperCase(); })
|
|
347
486
|
: defaults.safeMethods;
|
|
348
487
|
|
|
488
|
+
// #CSRF3 — Origin/Referer allowlist. Resolved once at factory time;
|
|
489
|
+
// throws if no usable origin can be resolved.
|
|
490
|
+
var allowedOrigins = resolveAllowedOrigins(opts.allowedOrigins, defaults.allowedOrigins);
|
|
491
|
+
|
|
349
492
|
var headerNameLower = headerName.toLowerCase();
|
|
350
493
|
|
|
351
494
|
return function ginaCsrf(req, res, next) {
|
|
@@ -382,6 +525,17 @@ function Csrf(opts) {
|
|
|
382
525
|
return next();
|
|
383
526
|
}
|
|
384
527
|
|
|
528
|
+
// #CSRF3 — Origin/Referer pre-filter. Layered ON TOP of the token
|
|
529
|
+
// check below: a forged token with a matching cookie still gets
|
|
530
|
+
// rejected here when the request didn't come from an allowed origin.
|
|
531
|
+
var requestOrigin = parseRequestOrigin(req);
|
|
532
|
+
if (!requestOrigin) {
|
|
533
|
+
return reject(req, res, 'missing origin/referer');
|
|
534
|
+
}
|
|
535
|
+
if (allowedOrigins.indexOf(requestOrigin) < 0) {
|
|
536
|
+
return reject(req, res, 'origin not allowed');
|
|
537
|
+
}
|
|
538
|
+
|
|
385
539
|
var presented = readPresentedToken(req, headerNameLower, fieldName);
|
|
386
540
|
var cookie = readCookie(req, cookieName);
|
|
387
541
|
|
|
@@ -418,6 +572,10 @@ Csrf._readCookie = readCookie;
|
|
|
418
572
|
Csrf._appendSetCookie = appendSetCookie;
|
|
419
573
|
Csrf._isSecureRequest = isSecureRequest;
|
|
420
574
|
Csrf._readPresentedToken = readPresentedToken;
|
|
575
|
+
Csrf._parseOriginString = parseOriginString; // #CSRF3
|
|
576
|
+
Csrf._parseRequestOrigin = parseRequestOrigin; // #CSRF3
|
|
577
|
+
Csrf._resolveBundleHostname = resolveBundleHostname; // #CSRF3
|
|
578
|
+
Csrf._resolveAllowedOrigins = resolveAllowedOrigins; // #CSRF3
|
|
421
579
|
Csrf._ALLOWED_ROTATE = ALLOWED_ROTATE;
|
|
422
580
|
Csrf._SESSIONLESS_MESSAGE = SESSIONLESS_MESSAGE;
|
|
423
581
|
Csrf._NONCE_BYTES = NONCE_BYTES;
|
|
@@ -161,13 +161,25 @@ function Session(expressSession) {
|
|
|
161
161
|
);
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
function ginaSessionDispatch(options) {
|
|
165
165
|
options = options || {};
|
|
166
166
|
var defaults = resolveSettingsDefaults();
|
|
167
167
|
options.cookie = mergeCookie(options.cookie, defaults);
|
|
168
168
|
assertInvariant(options.cookie);
|
|
169
169
|
return expressSession(options);
|
|
170
|
-
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
var wrapped = function (options) { return ginaSessionDispatch(options); };
|
|
173
|
+
|
|
174
|
+
// Drop-in identity: introspection (`session.name`) returns the upstream
|
|
175
|
+
// identity (`'session'`), while gina stays visible in stack traces via
|
|
176
|
+
// the inner `ginaSessionDispatch` frame. Without this, freelancer/v3 and
|
|
177
|
+
// other bundles that sniff `session.name === 'session'` saw `'ginaSession'`
|
|
178
|
+
// — the wrapper was clobbering the upstream identity.
|
|
179
|
+
Object.defineProperty(wrapped, 'name', {
|
|
180
|
+
value: expressSession.name,
|
|
181
|
+
configurable: true
|
|
182
|
+
});
|
|
171
183
|
|
|
172
184
|
// Preserve express-session's static surface (.Store, .MemoryStore,
|
|
173
185
|
// .Session, .Cookie). Consumers do `var MemoryStore = session.MemoryStore`
|
|
@@ -82,20 +82,27 @@
|
|
|
82
82
|
"secure": "auto"
|
|
83
83
|
}
|
|
84
84
|
},
|
|
85
|
-
// #CSRF2 — signed double-submit token middleware
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
85
|
+
// #CSRF2 / #CSRF3 — signed double-submit token middleware + Origin/Referer
|
|
86
|
+
// pre-filter applied by gina.plugins.Csrf(). The secret lives in
|
|
87
|
+
// `process.env.GINA_CSRF_SECRET` (NOT in this file) — generate with
|
|
88
|
+
// `openssl rand -base64 64` and store in env.json or your shell profile.
|
|
89
|
+
// cookieName — cookie name issued on safe methods
|
|
90
|
+
// headerName — request header read on mutating methods
|
|
91
|
+
// fieldName — form field read on mutating methods
|
|
92
|
+
// rotate — "per-session" (default) or "per-request"
|
|
93
|
+
// safeMethods — methods that issue without verifying (default GET/HEAD/OPTIONS)
|
|
94
|
+
// allowedOrigins — #CSRF3 allowlist matched against the request `Origin` header
|
|
95
|
+
// (or `Referer` host fallback) on mutating methods.
|
|
96
|
+
// Empty/unset = bundle's configured hostname only;
|
|
97
|
+
// non-empty = explicit allowlist (multi-domain bundles).
|
|
98
|
+
// Format: ["https://example.com", "https://www.example.com"].
|
|
93
99
|
"csrf": {
|
|
94
100
|
"cookieName": "gina-csrf-token",
|
|
95
101
|
"headerName": "X-Gina-CSRF-Token",
|
|
96
102
|
"fieldName": "_csrf",
|
|
97
103
|
"rotate": "per-session",
|
|
98
|
-
"safeMethods": ["GET", "HEAD", "OPTIONS"]
|
|
104
|
+
"safeMethods": ["GET", "HEAD", "OPTIONS"],
|
|
105
|
+
"allowedOrigins": []
|
|
99
106
|
},
|
|
100
107
|
"engine.io": {
|
|
101
108
|
// Reserved Gina infrastructure range: 4100–4199
|
package/gna.js
CHANGED
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
17
|
// Framework core — the main gna module (lifecycle hooks, lib, etc.)
|
|
18
|
-
var _gna = require('./framework/v0.3.
|
|
18
|
+
var _gna = require('./framework/v0.3.8/core/gna');
|
|
19
19
|
|
|
20
20
|
// SuperController and EntitySuper — loaded from their source modules
|
|
21
|
-
var SuperController = require('./framework/v0.3.
|
|
22
|
-
var EntitySuper = require('./framework/v0.3.
|
|
21
|
+
var SuperController = require('./framework/v0.3.8/core/controller');
|
|
22
|
+
var EntitySuper = require('./framework/v0.3.8/core/model/entity');
|
|
23
23
|
|
|
24
24
|
// uuid — from the lib registry
|
|
25
|
-
var uuid = require('./framework/v0.3.
|
|
25
|
+
var uuid = require('./framework/v0.3.8/lib/uuid');
|
|
26
26
|
|
|
27
27
|
module.exports = {
|
|
28
28
|
|
package/llms.txt
CHANGED
|
@@ -858,3 +858,15 @@ YAML indent trap: the heredoc body and the `EOF` terminator must land at column
|
|
|
858
858
|
74. **Vendored-dep `package.json` metadata carries CVE-visibility — never strip `dependencies`.** Supersedes #73's "strip" fix pattern. Vendored deps under `framework/v*/core/deps/` are supply-chain surface identical to npm-installed deps: Socket, Dependabot, and `npm audit` all read the sub-`package.json` files inside the published tarball, extract `(name, version)` pairs, follow `dependencies` edges, and match each against their CVE databases. Stripping `dependencies` (or `devDependencies`, or `scripts`) to "reduce Socket's dep count" removes that signal — even when the fields are "dead at runtime" because the vendored code resolves sibling deps via relative-path `require()`. The metadata is load-bearing for security tooling. **The invariant**: vendored `package.json` stays byte-identical to the upstream npm tarball until a local patch is applied. No strips, no reorders, no cleanups. **Patch discipline**: when gina needs to modify a vendored dep's source, bump its `version` from `<upstream>` to `<upstream>-rhinostone.N` (e.g. `1.6.0-rhinostone.1`). Semver-compliant (it's a prerelease identifier), so OSV/Socket/Dependabot's range-matching still hits the base upstream CVE record; the suffix is a read-the-tree-and-know-at-a-glance signal that the copy has diverged. Reset the counter on any upstream version bump. **Belt-and-suspenders**: `.github/workflows/vendored-cve.yml` runs a Node script (`.github/scripts/scan-vendored-cves.js`) on every push + weekly Sunday cron that walks `framework/v*/core/deps/*/package.json`, queries `api.osv.dev/v1/query` for each `(name, version)` pair (normalising away the `-rhinostone.N` suffix before querying), and fails the build on any matched vulnerability. Independent of whichever third-party scanner happens to be active on the published tarball — if Socket/Dependabot ever shifts methodology again, CVE coverage on vendored deps is still guaranteed locally. **Precedent**: `gina@0.3.7-alpha.5` stripped the vendored metadata per #73's (incorrect) advice — flagged the same day by a maintainer concern that `core/deps/` was no longer being scanned. Reverted in alpha.6 (commit `e5d5d0a2`) along with `.github/workflows/vendored-cve.yml` + `.claude/architecture/vendored-deps.md` documenting the discipline. Socket count went from 3 back to 4 (streamsearch edge restored); every entry is a truthful dep the scanners SHOULD see. **Key reframe**: supply-chain surface is not dep-count minimization — it's whether the scanners have the signal they need. An accurate count with CVE visibility beats an under-reported count with blind spots every time.
|
|
859
859
|
|
|
860
860
|
77. **Session cookies in gina are NOT framework-owned — they are issued by the bundle's own `app.use(session({...}))` call via `express-session`, so framework-level cookie hardening cannot be transparent without regressing intentional bundle choices.** The framework's `lib.SessionStore(session)` factory is a thin wrapper that receives the bundle's `express-session` module reference, reads `connectors.json[session.name].connector`, and returns a connector-specific Store class. It never holds a reference to the cookie options, and it runs once per bundle boot — long after the bundle's `index.js` has already captured `var session = require('express-session')` as a local. Nothing in `core/server.js`, `core/server.isaac.js`, or `core/server.express.js` writes `Set-Cookie` — those three files have zero grep matches on `cookie` and `set-cookie`. **Chokepoint analysis trap**: the single shared response entry at `core/server.js:2324` (`self.instance.all('*', function onInstance(request, response, next) { ... })`) does look like the natural place to wrap `response.setHeader` to post-process every `Set-Cookie` value, and Isaac + Express both route through it. But Set-Cookie strings carry no provenance: `Set-Cookie: sessionid=abc; Path=/; Secure` could be a bundle that never thought about `HttpOnly` (safe to add) OR a bundle that explicitly set `httpOnly: false` because a client-side validator or toolbar has to read `document.cookie` (adding `HttpOnly` breaks it). Inspecting three real bundles (`~/Sites/freelancer/v3/src/{auth,dashboard,public}/index.js`) showed all three deliberately set `httpOnly: false` and comment out `sameSite` — a transparent wrap would have silently regressed every one. This is exactly the failure mode CLAUDE.md's "Don't strip what you haven't surveyed" rule warns about, in its dual form: "don't ADD what the source didn't ask for either". **The correct shape for a cookie-hardening feature** is an opt-in plugin at `core/plugins/lib/session/src/main.js` that wraps `expressSession(options)` with a factory: reads `settings.json > session.cookie.{sameSite, httpOnly, secure}`, merges defaults into `options.cookie` only for flags the caller did NOT set (guarded by `Object.prototype.hasOwnProperty.call(caller, key)`), validates the browser-parity invariant (`SameSite=None` without `Secure` throws), and passes through. Adoption is a one-line swap in the bundle bootstrap: `var session = require('gina').plugins.Session(require('express-session'))`. Existing bundles that don't adopt continue working exactly as before; adopting is explicit and visible in the diff. **The measurement step that surfaced the trap**: before writing any code, grep real bundle code for cookie flag patterns — `grep -nE 'httpOnly|sameSite|secure[\s:]' ~/Sites/<project>/src/*/index.js`. If any bundle has deliberate `httpOnly: false` or `sameSite` commented out, transparent wrapping is off the table and the feature must be opt-in. Precedent: #CSRF1 (2026-04-24, shipped in `0.3.7-alpha.8`) — initial design pivoted from per-request `response.setHeader` wrap to opt-in `gina.plugins.Session` plugin after the Freelancer measurement showed three bundles with deliberate `httpOnly: false`. The plugin shape also becomes the natural seam for #CSRF2 (signed double-submit token middleware, planned for `0.3.8`), which needs a session-aware injection point — session hardening and CSRF token plumbing share the same mount scope.
|
|
861
|
+
|
|
862
|
+
78. **`git filter-repo` operational gotchas — second-run prompts, origin removal, committer-date SHA churn, and the local-only-tag false positive that makes a previously-cleaned repo *look* like it still has leaks.** Four traps in order: (1) **prior-run safety prompt** — if `.git/filter-repo/already_ran` exists from an earlier rewrite, the next run prints "Treat this run as a continuation of filtering in the previous run (Y/N)?" and reads stdin. `--force` does not bypass it. Pipe `echo Y |` for non-interactive runs. (2) **origin removed** — filter-repo deletes the `origin` remote at the end of every run by design ("so you don't accidentally push the rewritten history"). After the rewrite, `git remote add origin https://github.com/<owner>/<repo>.git` before any push. (3) **committer-date SHA churn** — filter-repo updates committer dates to "now" on every commit it walks, even when message and tree are unchanged. Every reachable commit gets a new SHA. Net effect: a no-op rewrite of an already-clean branch still produces a force-push divergence between local and origin. (4) **local-only-tag false positive** — `git log --all` reaches every ref, including local-only safety-net tags created by prior rewrites (`pre-rewrite-*-DATE`, `pre-history-scrub-*-DATE`). Those tags preserve un-substituted commits as personal backups. They are NOT on origin (verify with `git ls-remote origin 'refs/tags/pre-*'`) and therefore not violating the public-surface rule. Before re-running filter-repo on a previously-cleaned repo, check leak counts per branch with `git log <ref> --format='%s%n%b' | grep -iE '<patterns>' | wc -l` for each live branch individually — if all are zero, the live branches are clean and the only "leaks" left are in personal local-only tags that don't need rewriting. Precedent: 2026-04-25 second-pass leak scrub on gina-io/gina — comprehensive `git log --all` audit found 4 commit subjects + 3 commit bodies with descriptive feature mentions, but per-branch checks showed origin develop/master/dev/wip all already at 0 leaks. The remaining matches lived only in `pre-rewrite-*-20260421T233346Z` tags from a 2026-04-21 prior filter-repo. Today's filter-repo did push develop and dev/wip with cosmetically-different SHAs (force-pushed for nothing) before the per-branch verification surfaced that master was already clean. The reflex "saw leaks via `git log --all`, run filter-repo" needs the per-branch refinement step to avoid unnecessary force-push churn on tracking clones.
|
|
863
|
+
|
|
864
|
+
79. **GitHub branch protection — `allow_force_pushes: false` blocks ALL force-pushes including admin (independent of `enforce_admins`); the dedicated subfield REST endpoint for this flag does not exist.** Two non-obvious behaviors: (1) **flag interaction** — `enforce_admins: false` does NOT mean admins can force-push when `allow_force_pushes: false`. The two flags work on different rule categories: `enforce_admins` controls whether review-style protections (required reviews, status checks) apply to admin actors; `allow_force_pushes` is a flat protocol-level block on history rewriting that GitHub's git backend rejects regardless of admin status. So `enforce_admins: false` + `allow_force_pushes: false` means: admins can merge without review, but cannot force-push. To force-push to a protected branch as admin, `allow_force_pushes` must be flipped to `true` (temporarily) before the push, then back to `false` after. (2) **subfield endpoint absence** — GitHub's REST API documents per-subfield endpoints for some protection flags (`POST/DELETE /repos/.../protection/required_signatures`, `enforce_admins`), but `POST /repos/.../protection/allow_force_pushes` and `DELETE /repos/.../protection/allow_force_pushes` both return `404 Not Found`. The subfield API is partial. To toggle `allow_force_pushes`, use either the full `PUT /repos/.../protection` payload (with all required fields including `required_status_checks`, `enforce_admins`, `required_pull_request_reviews`, `restrictions` — null for those without rules), or `DELETE /repos/.../protection` to drop protection entirely then re-`PUT` to recreate. The web UI Settings → Branches → "Allow force pushes" toggle is also a clean path when an admin is at the keyboard. **Best non-destructive workflow** when force-push is needed for a one-off operation: have an admin lift via web UI → push → admin re-enables. The API path is brittle (the full-PUT payload must be reconstructed exactly to avoid losing other rule settings). Precedent: 2026-04-25 leak scrub — attempted `gh api -X POST repos/gina-io/gina/branches/master/protection/allow_force_pushes` to allow a force-push of master, got 404 (subfield endpoint absent), the push correctly failed, no protection state was modified (verified after via `gh api .../protection --jq`). The 404 was harmless — neither flip happened — but the master push didn't go through either. master turned out to already be clean from the prior rewrite, so no push was actually needed. **2026-04-26 update (gina@0.3.7 stable cut, master-reset session)** — UI toggle did NOT take effect. Two attempts via Settings → Branches → "Allow force pushes" → Save left the underlying state unchanged (force-push still rejected with `GH006: Protected branch update failed`). Classic protection settings looked normal; rulesets API was empty (no competing rule). API-fallback PUT (full payload, `allow_force_pushes: true`) worked first try; flipped back after the push. Possible causes: stale browser session, Org-level enforcement, UI bug. **Refined pattern**: if the UI doesn't take effect after one attempt (verify immediately with `gh api repos/<owner>/<repo>/branches/<branch>/protection --jq .allow_force_pushes.enabled`), fall back to API-PUT — don't retry the UI. Saves a round-trip on a class of failure that's hard to diagnose at the UI layer.
|
|
865
|
+
|
|
866
|
+
80. **Plan-vs-shipped attribute drift — when a multi-commit feature plan declares an interface attribute name, the shipped implementation may diverge, and downstream commits silently propagate the wrong name unless every fresh session re-grounds against the source.** The trap: a planning document or upstream commit prompt declares an interface attribute (e.g. "the plugin attaches the token to `req._csrfToken`"). The actual implementation, once written, names it differently (`req.csrfToken` — no underscore). Downstream commits that depend on the attribute (controller exposing it to template context, validator AJAX reading it off `req`, tests asserting on the name) all reference the original planned name unless their author re-verifies. The plan looks coherent; the code drifts. **Detection pattern**: every fresh agent session implementing a downstream commit must `grep -n '<attribute>' <upstream-source-file>` before referencing the attribute. If the plan and the source disagree, the source wins — re-read the plan, fix the references, flag the upstream-plan inconsistency in the session report so the planner can correct future-downstream prompts. **The source of truth for an in-flight feature is the shipped code on `develop`, not the upstream plan or prompt.** Plans rot the moment implementation deviates; planning hygiene means re-grounding every multi-commit feature against the latest develop tip before downstream work. Precedent: 2026-04-25 #CSRF2 implementation — the plan-of-record (commit-3 prompt) said `req._csrfToken`; commit-1's plugin attached `req.csrfToken` (verified at `core/plugins/lib/csrf/src/main.js:377,407`). The fresh agent for commit 3 caught it via the grep pattern and used the correct name, preventing silent wrong-attribute propagation into controller.js + 25 new tests + the planned docs guide.
|
|
867
|
+
|
|
868
|
+
81. **CI flake-vs-regression triage — when a CI run fails on a commit, look for a same-message-different-SHA pair before assuming the code is buggy.** Rebases or amends produce two commits with identical messages but different SHAs. If `gh run list --repo <owner>/<repo> --branch <branch> --limit 10 --json databaseId,conclusion,headSha,name,displayTitle` shows the earlier SHA passed Tests and the later SHA failed, run `git diff --stat A..B` between them — empty output proves byte-identical content. Same content + different CI outcome = environmental flake, not regression, and the test should not be touched (per the "Don't change existing tests unless asked" rule). **Reproduce shape matters**: a single-file local run (`node --test test/lib/<file>.test.js`) is necessary but not sufficient — CI invokes all four directories in one process (`node --test test/core/*.test.js test/lib/*.test.js test/bin/*.test.js test/integration/helper.test.js`), and module / parallelism state shape differs between the two. Reproduce with the **exact CI invocation** before falling back to a rerun. **Cheapest discriminator order**: (1) `git diff --stat` between same-message SHAs (proves content-identical, ~1 second); (2) full-suite local invocation with the exact CI command (proves logic-deterministic at scale, ~30s); (3) `gh run rerun <id> --repo <owner>/<repo>` if (1)+(2) survive — green retry confirms environmental flake, red retry escalates to CI-environment investigation (Node version drift, runner timing, fixture pollution across the parallel file dispatch). **Watchlist hygiene**: log single-occurrence flakes to a local post-mortem journal under "CI flake watchlist" — `gh run list` retention defaults to 90 days, so without a local note a recurrence in 6 months looks like a first occurrence. Two occurrences of the same flake on a deterministic in-memory test = pattern, not coincidence. Precedent: 2026-04-26 — `test/lib/collection.test.js > 05 - delete > delete: Hotel without ids WHERE country = France` flaked once on run #24938620953 (`d1ea0a72`, 2026-04-25, Node 24.14.1, Ubuntu); same-content earlier SHA `623e4232` had passed; full-suite local run was 3766/3766 clean; rerun went green. Watchlist entry filed in the local post-mortem journal.
|
|
869
|
+
|
|
870
|
+
82. **Source-inspection tests that assert source order — `src.indexOf('<funcName>(<args>)')` matches the function DEFINITION before the call site, not the call site.** When a test asserts "A must be called before B" via `indexOf` on a function-name-with-args fragment, the match lands on the `function <funcName>(<args>)` definition near the top of the file, not the call site lower in the body. If both names are defined in the same source-order as their call sites, the assertion accidentally passes for the wrong reason; if they're defined in a different order than they're called (helper defined first, used last), it fails for the wrong reason. **Discrimination test**: `grep -c '<pattern>' <file>` — if the count is > 1, the indexOf is ambiguous and the assertion is unreliable. **Fix**: search for a unique call-site fragment that doesn't appear in the function definition — typically the assignment LHS (`requestOrigin = parseRequestOrigin(req)`, `presented = readPresentedToken(req`). Definitions never contain the assignment target. Same trap applies to any pattern where definition and call share the same identifier syntax — method names, event listener attachments, even `console.error('[<feature>]'` template strings. Precedent: 2026-04-26 #CSRF3 implementation — section 14 source-inspection test "Origin pre-filter runs AFTER the csrfExempt short-circuit" failed at first because `indexOf('parseRequestOrigin(req)')` matched the `function parseRequestOrigin(req)` definition (line 152) before the call site (line 531); switched to `indexOf('requestOrigin = parseRequestOrigin(req)')` (assignment-form, unique to the call site). The sibling "BEFORE token verify" test passed only by coincidence — the `parseRequestOrigin` definition was already before the `readPresentedToken` definition in the file.
|
|
871
|
+
|
|
872
|
+
83. **`Origin: "null"` is a real value browsers send — sandboxed iframes (`<iframe sandbox>`), `file://` pages, and some redirected requests carry the literal string `"null"` in the Origin header (and in `Sec-Fetch-Site: cross-site` flows).** Origin-checking code that does `if (origin) { /* allowlist match */ }` treats `"null"` as truthy and tries to match it. Without an explicit guard the result is wrong-for-the-right-outcome at best: the allowlist almost never contains `"null"`, so the request 403s — but for the wrong reason (it should fall through to the Referer fallback or a known-no-origin handler, not be rejected for "origin not in allowlist"). The same trap applies to CORS allowlists, CSRF Origin pre-filters, audit logging, and any code branching on `Origin`. **Fix**: add an explicit `s === 'null'` guard at the start of the Origin parser, treating `"null"` exactly like an absent header — empty result, fall through to the next signal (Referer, Sec-Fetch metadata, etc.). Document the guard with a brief comment so it isn't "cleaned up" by a future contributor who reads it as a no-op string check. Precedent: 2026-04-26 #CSRF3 implementation — `parseOriginString` at `core/plugins/lib/csrf/src/main.js:108` returns `null` (the JS literal) when input is the string `"null"`, so `parseRequestOrigin` falls back to parsing the host out of `Referer`. Two unit tests pin this behaviour: `Origin: "null"` + missing `Referer` → 403 with reason "missing origin/referer"; `Origin: "null"` + valid `Referer` → next() called. Without the guard, the missing-Referer case would have 403'd with reason "origin not allowed", masking the real problem from any operator reading the log.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gina",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "Node.js MVC framework with built-in HTTP/2, multi-bundle architecture, and scope-based data isolation — no Express dependency",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nodejs",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"gina-container": "bin/gina-container",
|
|
57
57
|
"gina-init": "bin/gina-init"
|
|
58
58
|
},
|
|
59
|
-
"main": "./framework/v0.3.
|
|
59
|
+
"main": "./framework/v0.3.8/core/gna",
|
|
60
60
|
"types": "./types/index.d.ts",
|
|
61
61
|
"typesVersions": {
|
|
62
62
|
"*": {
|
|
@@ -78,7 +78,9 @@
|
|
|
78
78
|
"license": "MIT",
|
|
79
79
|
"readmeFilename": "README.md",
|
|
80
80
|
"dependencies": {
|
|
81
|
-
"
|
|
81
|
+
"@rhinostone/swig": "^1.6.0",
|
|
82
|
+
"engine.io": "^6.0.0",
|
|
83
|
+
"psl": "^1.15.0"
|
|
82
84
|
},
|
|
83
85
|
"devDependencies": {
|
|
84
86
|
"csso-cli": "4.0.2",
|
package/script/post_install.js
CHANGED
|
@@ -61,14 +61,44 @@ var getUserHome = function() {
|
|
|
61
61
|
// `colors` dependency removed in 0.3.1 — ANSI codes are now built into the logger.
|
|
62
62
|
// No temporary install needed.
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
// Framework lib registry is intentionally not loaded here. At install time the
|
|
65
|
+
// framework's nested deps (psl, @rhinostone/swig) may not yet be resolvable, and
|
|
66
|
+
// `lib/domain` would crash on `require('psl')`. Node's built-in `console` is
|
|
67
|
+
// sufficient for the install scripts; `console.setLevel` (a `lib.logger`-only
|
|
68
|
+
// method) is gated below.
|
|
66
69
|
|
|
67
70
|
var scriptPath = __dirname;
|
|
68
71
|
var ginaPath = (scriptPath.replace(/\\/g, '/')).replace('/script', '');
|
|
69
|
-
var help = require(ginaPath + '/utils/helper.js');
|
|
70
72
|
var pack = ginaPath + '/package.json';
|
|
71
73
|
pack = (isWin32()) ? pack.replace(/\//g, '\\') : pack;
|
|
74
|
+
|
|
75
|
+
// Pre-load framework helpers BEFORE utils/helper. utils/helper.js's init()
|
|
76
|
+
// calls `require('framework/v*/lib/logger')`, which itself requires
|
|
77
|
+
// `framework/v*/helpers` (lib/logger:64). When utils/helper is the outer
|
|
78
|
+
// caller of lib/logger, lib/logger blocks at its helpers require and the
|
|
79
|
+
// iteration's `_require` reloads path.js / task.js while lib/logger is still
|
|
80
|
+
// mid-load — their module-local `var console = require('../lib/logger')`
|
|
81
|
+
// then binds to a partial module.exports (= {}), so a later `console.debug`
|
|
82
|
+
// in `task.js#run()` throws TypeError. Pre-loading helpers here makes
|
|
83
|
+
// helpers/index.js the outer caller, so lib/logger completes inside
|
|
84
|
+
// context.js's trigger and the subsequent `_require` reloads of path.js/
|
|
85
|
+
// task.js see the full Logger singleton from cache.
|
|
86
|
+
// Filesystem-driven version discovery so this stays correct across version
|
|
87
|
+
// bumps that may temporarily skew package.json `version` and the framework
|
|
88
|
+
// directory name (e.g. during a patch release window).
|
|
89
|
+
try {
|
|
90
|
+
var _frameworkDir = fs.readdirSync(ginaPath + '/framework')
|
|
91
|
+
.filter(function(d) { return /^v/.test(d); })
|
|
92
|
+
.sort()
|
|
93
|
+
.pop();
|
|
94
|
+
if (_frameworkDir) {
|
|
95
|
+
require(ginaPath + '/framework/' + _frameworkDir + '/helpers');
|
|
96
|
+
}
|
|
97
|
+
} catch (_e) {
|
|
98
|
+
// best-effort preload; the actual install steps will surface any real failure
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
var help = require(ginaPath + '/utils/helper.js');
|
|
72
102
|
var helpers = null;
|
|
73
103
|
|
|
74
104
|
|
|
@@ -135,7 +165,10 @@ function PostInstall() {
|
|
|
135
165
|
|
|
136
166
|
if ( /^\-\-log-level\=/.test(args[i]) ) {
|
|
137
167
|
var logLevel = args[i].split(/\=/)[1];
|
|
138
|
-
|
|
168
|
+
// setLevel is a lib.logger method; Node's built-in console doesn't expose it.
|
|
169
|
+
if ( typeof(console.setLevel) === 'function' ) {
|
|
170
|
+
console.setLevel(logLevel, 'gina');
|
|
171
|
+
}
|
|
139
172
|
process.env.LOG_LEVEL=logLevel;
|
|
140
173
|
}
|
|
141
174
|
}
|
|
@@ -168,7 +201,8 @@ function PostInstall() {
|
|
|
168
201
|
]
|
|
169
202
|
};
|
|
170
203
|
console.warn('No `package.json` found for your project, creating one to avoid install exceptions');
|
|
171
|
-
lib
|
|
204
|
+
// Inlined to avoid loading the framework lib registry at install time.
|
|
205
|
+
fs.writeFileSync(projectPackageJsonObj.toString(), JSON.stringify(defaultPackageJsonContent, null, 4));
|
|
172
206
|
}
|
|
173
207
|
}
|
|
174
208
|
|
|
@@ -301,7 +335,7 @@ function PostInstall() {
|
|
|
301
335
|
try {
|
|
302
336
|
await promisify(funct)();
|
|
303
337
|
} catch (e) {
|
|
304
|
-
console.error(e.toString());
|
|
338
|
+
console.error(e && e.stack ? e.stack : e.toString());
|
|
305
339
|
process.exit(1);
|
|
306
340
|
return;
|
|
307
341
|
}
|