{"id":18389586,"url":"https://github.com/anseki/gnirts","last_synced_at":"2025-04-04T11:07:17.757Z","repository":{"id":36465633,"uuid":"40770903","full_name":"anseki/gnirts","owner":"anseki","description":"Obfuscate string literals in JavaScript code.","archived":false,"fork":false,"pushed_at":"2025-02-22T02:23:07.000Z","size":150,"stargazers_count":110,"open_issues_count":0,"forks_count":15,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-28T10:08:30.719Z","etag":null,"topics":["cryptography","gnirts","hexadecimal-escape","javascript","literal","mangle","obfuscate","obfuscated","obfuscation","obfuscator","password","secret","security","string","string-literals"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"ludicrousxyz/light","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anseki.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-08-15T16:29:35.000Z","updated_at":"2025-03-20T02:56:05.000Z","dependencies_parsed_at":"2024-06-18T16:44:12.121Z","dependency_job_id":"7f87762d-a625-4467-a3fa-ae1b5dd34d21","html_url":"https://github.com/anseki/gnirts","commit_stats":{"total_commits":60,"total_committers":2,"mean_commits":30.0,"dds":"0.033333333333333326","last_synced_commit":"f59b213a15b1388fe92b10f54e7bc466a69d9f5a"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anseki%2Fgnirts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anseki%2Fgnirts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anseki%2Fgnirts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anseki%2Fgnirts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anseki","download_url":"https://codeload.github.com/anseki/gnirts/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247166164,"owners_count":20894654,"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","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":["cryptography","gnirts","hexadecimal-escape","javascript","literal","mangle","obfuscate","obfuscated","obfuscation","obfuscator","password","secret","security","string","string-literals"],"created_at":"2024-11-06T01:43:49.467Z","updated_at":"2025-04-04T11:07:17.716Z","avatar_url":"https://github.com/anseki.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gnirts\n\n[![npm](https://img.shields.io/npm/v/gnirts.svg)](https://www.npmjs.com/package/gnirts) [![GitHub issues](https://img.shields.io/github/issues/anseki/gnirts.svg)](https://github.com/anseki/gnirts/issues) [![dependencies](https://img.shields.io/badge/dependencies-No%20dependency-brightgreen.svg)](package.json) [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\n* [Grunt](http://gruntjs.com/) plugin: [grunt-gnirts](https://github.com/anseki/grunt-gnirts)\n* [gulp](http://gulpjs.com/) plugin: [gulp-gnirts](https://github.com/anseki/gulp-gnirts)\n* [webpack](https://webpack.js.org/) loader: [gnirts-loader](https://github.com/anseki/gnirts-loader)\n\nObfuscate string literals in JavaScript code.\n\n**\u003ca href=\"https://anseki.github.io/gnirts/\"\u003eOnline Demonstration https://anseki.github.io/gnirts/\u003c/a\u003e**\n\ngnirts mangles string literals more than hexadecimal escape like `\"\\x66\\x6f\\x6f\"`.  \nString literals that were escaped by the hexadecimal escape can be found out too easily, and those can be decoded too easily. Those stand out in the code. Stealers can get secret text (e.g. password) easily by pasting that on a console (e.g. Developer Tools of web browser).\n\ngnirts mangles string literals by using some codes instead of hexadecimal escape. gnirts might not be able to protect the string from stealers perfectly, but it forces a troublesome work upon them. (See [Note](#note).)\n\nFor example, a string that should be hidden is here:\n\n```js\nvar password = 'open sesame';\n```\n\nAdd the directives:\n\n```js\nvar password = /* @mangle */ 'open sesame' /* @/mangle */;\n```\n\nAnd then, pass this code to gnirts. The string literal between `/* @mangle */` and `/* @/mangle */` is obfuscated:\n\n```js\nvar password = (function(){var v=Array.prototype.slice.call(arguments),V=v.\nshift();return v.reverse().map(function(U,o){return String.fromCharCode(U-V-0-o)\n}).join('')})(6,119,117)+(527).toString(36).toLowerCase()+(function(){var N=\nArray.prototype.slice.call(arguments),O=N.shift();return N.reverse().map(\nfunction(R,T){return String.fromCharCode(R-O-41-T)}).join('')})(36,193,109)+(532\n).toString(36).toLowerCase()+(function(){var R=Array.prototype.slice.call(\narguments),E=R.shift();return R.reverse().map(function(g,v){return String.\nfromCharCode(g-E-62-v)}).join('')})(52,224,211)+(14).toString(36).toLowerCase();\n```\n\n(For this document, line-breaks were added to the code above.)\n\nHowever, the code above is no good because the `password` variable can be shown by the debugger (e.g. Developer Tools of web browser).  \nTherefore, using no variable is better way. And gnirts supports the checking that the string matches.  \nFor example, check whether an input from user is matched to a string literal:\n\n```js\nif (userInput === 'open sesame') {\n  console.log('OK, the door will be opened.');\n}\n```\n\nAdd the directives (Note that all of the condition expression is included in the directive):\n\n```js\nif (/* @mangle */ userInput === 'open sesame' /* @/mangle */) {\n  console.log('OK, the door will be opened.');\n}\n```\n\nAnd then, pass this code to gnirts. The condition expression between `/* @mangle */` and `/* @/mangle */` is obfuscated:\n\n```js\nif ((userInput).indexOf((function(){var f=Array.prototype.slice.call(arguments),\nL=f.shift();return f.reverse().map(function(U,d){return String.fromCharCode(U-L-\n54-d)}).join('')})(43,200,207,194),8)===8\u0026\u0026(new RegExp('^[^]{5}'+(18).toString(\n36).toLowerCase().split('').map(function(p){return String.fromCharCode(p.\ncharCodeAt()+(-13))}).join('')+(43023).toString(36).toLowerCase()+(18).toString(\n36).toLowerCase().split('').map(function(u){return String.fromCharCode(u.\ncharCodeAt()+(-13))}).join('')+(42989).toString(36).toLowerCase()+(18).toString(\n36).toLowerCase().split('').map(function(S){return String.fromCharCode(S.\ncharCodeAt()+(-13))}).join('')+(43023).toString(36).toLowerCase())).test(\nuserInput)\u0026\u0026(userInput).indexOf((function(){var I=Array.prototype.slice.call(\narguments),s=I.shift();return I.reverse().map(function(E,t){return String.\nfromCharCode(E-s-8-t)}).join('')})(38,82,159,149,159,157),0)===0) {\n  console.log('OK, the door will be opened.');\n}\n```\n\n(For this document, line-breaks were added to the code above.)\n\n## Directive\n\n2 styles of the directive are supported:\n\n```js\n/* @mangle */ TARGET_CODE /* @/mangle */\n```\n\n```js\n// @mangle\nTARGET_CODE\n// @/mangle\n```\n\n`TARGET_CODE`s are string literal or condition expression.\n\nThe comments in the target code are ignored.\n\n```js\n/* @mangle */ 'open' + /* Color: */' black' + ' sesame' /* @/mangle */\n```\n\n```js\n// @mangle\n'open' +\n// Color of sesame is here:\n' black' +\n' sesame'\n// @/mangle\n```\n\nDon't put a directive into a comment (i.e. don't make that be nested comment).\n\nThe target code in the directive are replaced to obfuscated codes.  \nThe replaced code differs depending on the inside code of the directive:\n\n### String literal\n\nThe string literals like `'foo'`, `\"foo\"` or `'foo' + 'bar'` are replaced to the codes that return an original string.\n\nFor example:\n\n```js\nvar password = /* @mangle */ 'open sesame' /* @/mangle */;\n```\n\nThe following strings at the left side and the right side of the string literal are copied to the same position of the replaced code:\n\n- `(`, `)`, `+`, `,`, `:`, `;`, `=`, `?`, `[`, `]`, `{`, `}`\n\nFor example:\n\n```js\npassword =\n  'open' +\n  // @mangle\n  ' white' +\n  ' sesame' + // \u003c- This `+` is copied.\n  // @/mangle\n  ' street';\n```\n\n```js\ndata = {\n  password:\n    // @mangle\n    'open sesame', // \u003c- This `,` is copied.\n    // @/mangle\n  userName: 'Ali Baba'\n};\n```\n\n### Condition expression\n\nThe condition expressions like `SOMETHING === 'string literal'` are replaced to the codes that return a boolean to indicate whether it matches.  \n`SOMETHING` may be a variable, a reference to a string like `fooObject.barProperty` or a function that returns a string. Note that `SOMETHING` may be referenced multiple times (i.e. if that is a function, that is called multiple times).  \nA comparison operator must be `===`, `==`, `!==` or `!=`.  \nThe string literal may be `'foo'`, `\"foo\"` or `'foo' + 'bar'`.\n\nFor example:\n\n```js\nif (/* @mangle */ userInput === 'open sesame' /* @/mangle */) {\n  console.log('OK, the door will be opened.');\n}\n```\n\nThe following strings at the left side and the right side of the condition expression are copied to the same position of the replaced code:\n\n- `\u0026\u0026`, `||`, `(`, `)`, `,`, `:`, `;`, `=`, `?`, `[`, `]`, `{`, `}`\n\nFor example:\n\n```js\nif (userName === 'Ali Baba' \u0026\u0026\n    // @mangle\n    userInput === 'open sesame' \u0026\u0026 // \u003c- This `\u0026\u0026` is copied.\n    // @/mangle\n    cave.hasTreasure) {\n  console.log('OK, the door will be opened.');\n}\n```\n\n```js\nvar message =\n  // @mangle\n  userInput === 'open sesame' ? // \u003c- This `?` is copied.\n  // @/mangle\n  'OK' :\n  'NO';\n```\n\n## Installation\n\n```console\nnpm install gnirts\n```\n\n## Methods\n\n### `mangle`\n\n```js\nobfuscatedCode = gnirts.mangle(sourceCode)\n```\n\nParse and mangle `sourceCode`, and return an obfuscated code.\n\nFor example:\n\n```js\nvar gnirts = require('gnirts'),\n  fs = require('fs'),\n  js;\n\njs = fs.readFileSync('src.js', {encoding: 'utf8'});\njs = gnirts.mangle(js);\nfs.writeFileSync('dest.js', js);\n```\n\n### `getCode`\n\n```js\nstringCode = gnirts.getCode(stringValue)\n```\n\nReturn a obfuscated code that returns a `stringValue`.\n\n## Note\n\nThis mangling is not the cryptography to keep the data secure. It is used to avoid the hacking, the stealing something or the reverse engineering for such as the hybrid applications or the web applications. If your program uses the sensitive information such as the user's accounts, you should consider the standard secure system such as the cryptography by key pair.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanseki%2Fgnirts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanseki%2Fgnirts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanseki%2Fgnirts/lists"}