{"id":28398404,"url":"https://github.com/primus/mirage","last_synced_at":"2025-10-08T07:19:37.883Z","repository":{"id":57298227,"uuid":"20865626","full_name":"primus/mirage","owner":"primus","description":"On Cybertron, he was one of the planet’s elite upper class, in Primus he provides a transparent persistent session id.","archived":false,"fork":false,"pushed_at":"2022-12-31T19:50:02.000Z","size":56,"stargazers_count":10,"open_issues_count":3,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-09-19T00:41:04.152Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/primus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-06-15T21:20:49.000Z","updated_at":"2022-12-31T19:45:35.000Z","dependencies_parsed_at":"2023-01-31T19:46:06.979Z","dependency_job_id":null,"html_url":"https://github.com/primus/mirage","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/primus/mirage","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/primus%2Fmirage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/primus%2Fmirage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/primus%2Fmirage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/primus%2Fmirage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/primus","download_url":"https://codeload.github.com/primus/mirage/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/primus%2Fmirage/sbom","scorecard":{"id":745113,"data":{"date":"2025-08-11","repo":{"name":"github.com/primus/mirage","commit":"d97bb0387c5ed6b9bc2baf9dc57d2910944439f5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.4,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/11 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/primus/mirage/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/primus/mirage/ci.yml/master?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/ci.yml:22","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 19 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-22T18:29:13.683Z","repository_id":57298227,"created_at":"2025-08-22T18:29:13.683Z","updated_at":"2025-08-22T18:29:13.683Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278904851,"owners_count":26066169,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-01T04:38:40.637Z","updated_at":"2025-10-08T07:19:37.877Z","avatar_url":"https://github.com/primus.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mirage\n\n[![Version npm](https://img.shields.io/npm/v/mirage.svg?style=flat-square)](https://www.npmjs.com/package/mirage)[![CI](https://img.shields.io/github/actions/workflow/status/primus/mirage/ci.yml?branch=master\u0026label=CI\u0026style=flat-square)](https://github.com/primus/mirage/actions?query=workflow%3ACI+branch%3Amaster)\n\nSome might say that Mirage was created with a silver sparkplug in his mouth. On\nCybertron, he was one of the planet's elite upper class, preferring to spend his\ndays hunting turbo-foxes instead of involving himself in conflict. He is armed\nwith a rifle which fires explosive, armor-piercing darts, but the most important\npiece of his arsenal in his function as a spy is his shoulder-mounted\nelectro-disruptor, which can bend photons to make Mirage invisible, or appear to\nbe where he is not, or even alter his physical appearance, hence his name.\n\nHis invisibility is invaluable for Primus. He now spends his time validating and\ngenerating session ids without the user even know it's there. It's a fully\ntransparent process, it's invisible, it's Mirage. The generated session ids can\nbe persisted if needed.\n\n## Installation\n\nThis is a plugin for the Primus framework and can be installed using `npm`:\n\n```\nnpm install --save mirage\n```\n\nThe `--save` tells `npm` to automatically add the installed version to your\npackage.json.\n\nThis module assumes that you're using either the [`primus-emit`](https://github.com/primus/emit)\nor the [`primus-emitter`](https://github.com/cayasso/primus-emitter) module,\nfor emitting events. Please see their sites to get detailed installation\ninstructions.\n\n## Table of Contents\n\n- [Usage server](#usage-server)\n  - [primus.id.timeout](#primusidtimeout)\n  - [primus.id.generator](#primusidgenerator)\n  - [primus.id.validator](#primusidvalidator)\n- [Usage client](#usage-client)\n\n## Usage server\n\nThe `mirage` plugin should be the first plugin you load in Primus. This is\nbecause it will buffer incoming messages while it's validating or generating\nan id. If you don't do this, **you will experience loss of data/messages!**.\nEven the [`fortess-maximus`](https://github.com/primus/fortress-maximus) plugin,\nthat is generally added as the first plugin, should be loaded after `mirage`.\n\nTo add this plugin to your Primus server simply call the `.plugin` method on the\nPrimus instance:\n\n```js\nprimus.plugin('mirage', require('mirage'));\n```\n\nNow that you've added the plugin, a new object, `.id` is available on your Primus\ninstance. This object allows you to interact with the `mirage` plugin.\n\n### primus.id.timeout\n\nThe maximum time it should take to validate or generate a session id. If\na timeout occurs all messages will be flushed and the callback will be called\nwith an error. You can assign the timeout directly using:\n\n```js\nprimus.id.timeout = 2000;\n```\n\nIt's also possible to configure this value using the `mirage timeout` option\nin the Primus constructor:\n\n```js\nvar primus = new Primus(httpsserver, {\n  'transformer': 'engine.io',\n  'mirage timeout': 5000\n});\n```\n\n### primus.id.generator\n\nThe generator method allows you to assign a custom id generator. By default we\ngenerate 8 random bytes using the `crypto` module. To set your own generator\nsimply call the `primus.id.generator` with the function that you want to use.\n\nThe supplied function will receive 2 arguments:\n\n1. `spark` A reference to the spark instance that is attempting to connect to\n   your server.\n2. `function` An error first callback which assumes to receive an error as first\n   argument if generation failed and the generated id as second argument.\n\n```js\nprimus.id.generator(function generate(spark, fn) {\n  asyncLookup(spark.query.customquerystring, function (err, account) {\n    if (err) return fn(err);\n\n    fn(undefined, account._id);\n  });\n});\n```\n\n### primus.id.validator\n\nThe validator method is called when we receive a pre-defined id. By default\nwe just allow all the things, but this can be overridden by supplying the\n`primus.id.validator` with a custom validator function.\n\nThe supplied function will receive 2 arguments:\n\n1. `spark` A reference to the spark instance that is attempting to connect to\n  your server.\n2. `function` An error first callback. If you fail to validate the id, we assume\n  that you pass this function an `Error` instance as first argument.\n\n```js\nprimus.id.validator(function validator(spark, fn) {\n  accountdb.exists(spark.mirage, function (err, exists) {\n    if (!err \u0026\u0026 !exists) err = new Error('Invalid id');\n\n    fn(err);\n  });\n});\n```\n\nAs you can see in the example above, the mirage `id` is introduced on the spark\nas `spark.mirage`. You can use this id to validate the connection. Now there are\ncases where you don't want to end the connection by supplying the callback with\nan error but you actually want to re-set a new session id. Well that's also\npossible with the validator as it can also act as a generator. To generate a\nnew session id you can call the callback with the new id as the second argument:\n\n```js\nprimus.id.validator(function validate(spark, fn) {\n  if (spark.mirage === 'old') return fn(undefined, 'new');\n  if (spark.mirage === 'new') return fn(undefined, 'old');\n\n  fn(new Error('The id is neither new or old'));\n});\n```\n\n## Usage client\n\nThe plugin also ships with a client API. This client API can be used for\npersisting the sessions across reconnects, refreshes and more. To re-use an id\nsimply add the `mirage` option in the client when connecting.\n\n```js\nvar socket = new Primus('https://example.org', {\n  mirage: readcookie('sessionid')\n});\n```\n\nWhen you receive a new session id from the server we emit a `mirage` event:\n\n```js\nsocket.on('mirage', function (id) {\n  savecookie('sessionid', id);\n});\n```\n\nThe id is also always available at: `socket.mirage`, but this is only after the\nconnection has generated an id or if you've manually supplied it.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprimus%2Fmirage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprimus%2Fmirage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprimus%2Fmirage/lists"}