{"_id":"legid","_rev":"4-b87852d43ba172e414ee98e82655856a","name":"legid","dist-tags":{"latest":"0.1.4"},"versions":{"0.1.0":{"name":"legid","version":"0.1.0","keywords":[],"author":{"name":"Shu Ding","email":"g@shud.in"},"license":"MIT","_id":"legid@0.1.0","maintainers":[{"name":"quietshu","email":"g@shud.in"}],"dist":{"shasum":"8f503272f2e4a3cdd58d1d9e6ecbeefee772ad32","tarball":"https://registry.npmjs.org/legid/-/legid-0.1.0.tgz","fileCount":5,"integrity":"sha512-r9n7BEELX4hbBpLTnhzSIMRNwZCIDRJ5SGa/wlXWlPtv8wAAf/jf85FTuqAW7JlCN1jzcqr9xeo7OVw2q7SARA==","signatures":[{"sig":"MEUCIQD+2ObTCyx1S187EfiIqb0fFJYM9Mdlas6aqJBkv6ct2QIgc1TmGVp9kLXAopyOdbw66CKC26gw9hRR6YfjdC6Xi7Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":12055},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","gitHead":"b065df1eacf4f1dffcc64b5631730636d302534a","scripts":{"test":"bunchee && node test.js","build":"bunchee"},"_npmUser":{"name":"quietshu","email":"g@shud.in"},"_npmVersion":"10.9.2","description":"A library for generating and validating IDs","directories":{},"_nodeVersion":"22.13.1","dependencies":{"@swc/helpers":"^0.5.17"},"_hasShrinkwrap":false,"devDependencies":{"bunchee":"^6.5.4","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/legid_0.1.0_1752226646428_0.36804428419915314","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"legid","version":"0.1.2","keywords":["id","identifier","validation","unique","random"],"author":{"name":"Shu Ding","email":"g@shud.in"},"license":"MIT","_id":"legid@0.1.2","maintainers":[{"name":"quietshu","email":"g@shud.in"}],"dist":{"shasum":"ecb28a2a395c471f1662de0c983d7d90de6e38c0","tarball":"https://registry.npmjs.org/legid/-/legid-0.1.2.tgz","fileCount":5,"integrity":"sha512-4VnEn3JN6fwVNTcR+3nF2JdM67vUZ2LMyKLl5iy51JGMD5DivQglynOs3JKtnMfrTT4NO9MRx9DKIbAV7FNd0g==","signatures":[{"sig":"MEUCIC0aHlp61N6JEG8HgZnwSqg4jv7saygzAhLYijr3wuC1AiEAyz9tU8u5+/UWvNh6mkXsOP4f8JR+zNKx7pafgtg4qAc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15343},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","gitHead":"559d7f17e5818434378e41f8a4e07dc8a8c13837","scripts":{"test":"bunchee && node test.js","build":"bunchee"},"_npmUser":{"name":"quietshu","email":"g@shud.in"},"_npmVersion":"10.9.2","description":"A library for generating safe, legit and random URL-safe IDs","directories":{},"_nodeVersion":"22.13.1","dependencies":{"@swc/helpers":"^0.5.17"},"_hasShrinkwrap":false,"devDependencies":{"bunchee":"^6.5.4","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/legid_0.1.2_1752230818371_0.43308808532207355","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"legid","version":"0.1.3","keywords":["id","identifier","validation","unique","random"],"author":{"name":"Shu Ding","email":"g@shud.in"},"license":"MIT","_id":"legid@0.1.3","maintainers":[{"name":"quietshu","email":"g@shud.in"}],"dist":{"shasum":"4dd8b11f1defcfaef42ff1143300e16ef0c67075","tarball":"https://registry.npmjs.org/legid/-/legid-0.1.3.tgz","fileCount":6,"integrity":"sha512-Md/YEbVG0vw1hSPxtUTpgMU4lp9g+Izy6+nRDDh5i0Prcvjbzvdjm4EEoaFfakP5/sZP0uC+o8G3pBB2Y0yAJg==","signatures":[{"sig":"MEQCIELJDrjpxGqlU24GspysGy+Kl/Tp3ZICkjAL1f1uaO2EAiBdR51aB82etGhW3+gAERltD/e6LMSg7ozQX23H53sdqg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":16491},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","gitHead":"1d4a6ff86be7c433089266527c7917876708ec24","scripts":{"test":"bunchee && node test.js","build":"bunchee"},"_npmUser":{"name":"quietshu","email":"g@shud.in"},"_npmVersion":"10.9.2","description":"A library for generating safe, legit and random URL-safe IDs","directories":{},"_nodeVersion":"22.13.1","dependencies":{"@swc/helpers":"^0.5.17"},"_hasShrinkwrap":false,"devDependencies":{"bunchee":"^6.5.4","typescript":"^5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/legid_0.1.3_1752238853717_0.8840643513549964","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"legid","version":"0.1.4","description":"A library for generating safe, legit and random URL-safe IDs","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"build":"bunchee","test":"bunchee && node test.js"},"keywords":["id","identifier","validation","unique","random"],"author":{"name":"Shu Ding","email":"g@shud.in"},"license":"MIT","devDependencies":{"badwords-list":"2.0.1-4","bunchee":"^6.5.4","typescript":"^5.8.3"},"packageManager":"pnpm@9.15.9","_id":"legid@0.1.4","gitHead":"1eaf99777bd98e306cbc0f4c576d7d755e52844f","_nodeVersion":"22.13.1","_npmVersion":"10.9.2","dist":{"integrity":"sha512-SlKVLZT+D+reRjCyJ6MdPar3qZnyogOl7LjlQ+0NaDTd4hDaKYG2hGjJ7ZT1cOgXB3DAw6Lo7uHoRwbgN1HfsQ==","shasum":"ba5d97084f31f0a5228fcc4036014ee6d3e165f4","tarball":"https://registry.npmjs.org/legid/-/legid-0.1.4.tgz","fileCount":5,"unpackedSize":12375,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBx/PvYcQjm8vyH7J5GlQq+GiGZTe5FA0OviEUITigqcAiA11LYIpvVxor4WtIGiq2SXLseEKKLs3XHm02+EuaXJRg=="}]},"_npmUser":{"name":"quietshu","email":"g@shud.in"},"directories":{},"maintainers":[{"name":"quietshu","email":"g@shud.in"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/legid_0.1.4_1752506503142_0.30227587222800945"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-11T09:37:26.426Z","modified":"2025-07-14T15:21:43.539Z","0.1.0":"2025-07-11T09:37:26.588Z","0.1.2":"2025-07-11T10:46:58.535Z","0.1.3":"2025-07-11T13:00:53.949Z","0.1.4":"2025-07-14T15:21:43.324Z"},"author":{"name":"Shu Ding","email":"g@shud.in"},"license":"MIT","keywords":["id","identifier","validation","unique","random"],"description":"A library for generating safe, legit and random URL-safe IDs","maintainers":[{"name":"quietshu","email":"g@shud.in"}],"readme":"# legid\n\nA library for generating __safe__, __legit__ and __random__ URL-compat IDs.\n\nUnlike other random ID libs, Legid is to solve the __client-side manipulation__ problem. Read the example below.\n\n## Why use Legid?\n\nIn a modern web application, you often need to generate short and unique IDs\n__on the client side__:\n\n```typescript\n<button onClick={async () => {\n  // Some function to generate a random ID\n  const id = generateId()\n\n  // Optimistically update the URL so the user will see the page immediately\n  router.push(`/tweet/${id}`)\n\n  // Send the actual request to post the tweet\n  await createTweet(id, content)\n}}>\n  Submit Tweet\n</button>\n```\n\nUsually, you would use a random string generator or just a UUID. However, the\nmain problem with these approaches is __client-side manipulation and man-in-the-middle\nattacks__.\n\nFor example, if a malicious user overrides the client `generateId` implementation\nvia browser developer tools to return an ID of their choice, such as `\"admin\"`, the server\nwould accept it without any verification. And suddenly, the user successfully created a tweet\nwith the special URL `/tweet/admin`, which is not what we want to happen.\n\nUsually, this can be solved by generating the ID on the server side, or by using\nboth an ID and a verification token/nonce. But we want to avoid:\n\n- Extra network request before knowing the ID\n- Storing pre-generated IDs on the server\n- Sending one-off tokens or nonces between client and server\n- Using a wordlist on the server to filter out not-allowed IDs\n\n__Legid__ is here to solve this problem.\n\n## Features\n\nThe `legid` library provides a simple and secure way to generate and verify IDs that\nonly consist of URL-safe characters (A-Z, a-z, 0-9). It is designed to be:\n\n- **Safe to use on the client side**\n  - Avoids manipulation\n  - Prevents malicious tampering\n- **Easy to verify on the server side**\n  - No nounce or shared secret necessary between client and server\n  - No extra token or verification step required\n\n## Usage\n\n```bash\npnpm install legid\n```\n\n### Client side\n\nCreate a random ID string:\n\n```typescript\nimport { createId } from 'legid'\n\nconst id = await createId()\n\n// Example: 'e3N4BRJW2d'\n```\n\nSpecify the custom ID length (approximate) and hash salt (see below) if needed:\n\n```typescript\nimport { createId } from 'legid'\n\nconst id = await createId({\n  approximateLength: 20,  // Custom length, default is 10\n  salt: 'my-custom-salt', // Custom salt, default is 'legid:'\n})\n\n// Example: 'gnzJb1TCJobhuG4PrIZz'\n```\n\nIt’s safe to expose the salt on the client side, as it is not a secret. Make\nsure the verification on the server side uses the same salt.\n\n### Server side\n\nUse the verify function to check if an ID is valid:\n\n```typescript\nimport { verifyId } from 'legid'\n\n// Server Side\nconst isValid = await verifyId(id)\n```\n\nWhen `isValid` is `false`, the ID is either malformed or not generated by `legid`.\n\nThe `verifyId` function can also accept a custom salt just like `createId`:\n\n```typescript\nimport { verifyId } from 'legid'\n\nconst isValid = await verifyId(id, {\n  salt: 'my-custom-salt', // Custom salt, default is 'legid:'\n})\n```\n\n## How it works\n\nThe generated ID consists of a random data buffer with its SHA-1 hash. These 2 parts\nare mixed together at odd and even positions, respectively, and then converted to a custom\nalphabet (A-Z, a-z, 0-9). The SHA-1 hash is salted with a prefix to prevent rainbow table attacks.\n\nThe reversed process is used to verify the ID.\n\nThis means that if a malicious user tries to generate an ID with a specific value,\nlet’s say `\"admin\"`, conceptually they need to ensure that `SHA1(salt + \"di\")` starts with `\"amn\"` so the mixed ID would be `\"admin\"`. This is very unlikely to happen, at least not with a reasonable amount of effort.\n\n## Note\n\n**While this is not a cryptographic solution**, it is designed to make it difficult\nto manipulate the ID with lowest effort. It is not intended for use in\ncryptographic applications or where high security is required.\n\nCollisions are still possible. The format Legid uses will decrease the possible generation space. For a given length L, there will be approximately 62^(L/2) IDs available. __You should always check collision and ID length on the server side before proceeding.__\n\nPossible adjustments can be made to this lib by changing RHRHRH (R for random data position, H for hash positions) to other representations like HRRHRR to reduce the collision rate with a compromise of security.\n\n## Author\n\nCreated by [Shu Ding](https://x.com/shuding_) [@vercel](https://vercel.com).\n\n## License\n\nThe MIT License.\n","readmeFilename":"README.md"}