{"id":19122955,"url":"https://github.com/digitalbazaar/hashlink","last_synced_at":"2025-05-05T18:28:45.562Z","repository":{"id":53008127,"uuid":"198871675","full_name":"digitalbazaar/hashlink","owner":"digitalbazaar","description":"JavaScript implementation of Cryptographic Hyperlinks specification.","archived":false,"fork":false,"pushed_at":"2023-01-14T00:53:39.000Z","size":95,"stargazers_count":13,"open_issues_count":6,"forks_count":3,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-04-14T18:54:08.130Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://tools.ietf.org/html/draft-sporny-hashlink","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/digitalbazaar.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2019-07-25T17:07:38.000Z","updated_at":"2022-11-15T05:37:31.000Z","dependencies_parsed_at":"2023-02-09T18:16:57.129Z","dependency_job_id":null,"html_url":"https://github.com/digitalbazaar/hashlink","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalbazaar%2Fhashlink","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalbazaar%2Fhashlink/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalbazaar%2Fhashlink/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalbazaar%2Fhashlink/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/digitalbazaar","download_url":"https://codeload.github.com/digitalbazaar/hashlink/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252552590,"owners_count":21766728,"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":[],"created_at":"2024-11-09T05:23:44.068Z","updated_at":"2025-05-05T18:28:45.491Z","avatar_url":"https://github.com/digitalbazaar.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Javascript Cryptographic Hyperlinks Library _(hashlink)_\n\n[![NPM Version](https://img.shields.io/npm/v/hashlink.svg)](https://npm.im/hashlink)\n[![Build status](https://img.shields.io/github/workflow/status/digitalbazaar/hashlink/Node.js%20CI)](https://github.com/digitalbazaar/hashlink/actions?query=workflow%3A%22Node.js+CI%22)\n[![Coverage status](https://img.shields.io/codecov/c/github/digitalbazaar/hashlink)](https://codecov.io/gh/digitalbazaar/hashlink)\n\nA Javascript library for encoding, decoding, and verifying hashlinks as\ndefined in the\n[IETF Hashlink draft spec](https://tools.ietf.org/html/draft-sporny-hashlink).\n\nExample Hashlinks:\n\n- Regular Hashlink (without URL encoded)\n  - `hl:zm9YZpCjPLPJ4Epc`\n- Regular Hashlink (with URL encoded):\n  - `hl:zm9YZpCjPLPJ4Epc:z3TSgXTuaHxY2tsArhUreJ4ixgw9NW7DYuQ9QTPQyLHy`\n- Hashlink as a query parameter:\n  - `https://example.com/hw.txt?hl=zm9YZpCjPLPJ4Epc`\n\n## Table of Contents\n\n- [Security](#security)\n- [Background](#background)\n- [Install](#install)\n- [Usage](#usage)\n- [API](#api)\n- [Testing](#testing)\n- [Contribute](#contribute)\n- [Commercial Support](#commercial-support)\n- [License](#license)\n\n## Security\n\nSecurity is hard. Cryptography is harder. When in doubt, leave it to the\nprofessionals.\n\nWhile the authors of this library are professionals, and they have used\ncryptographic primitives and libraries written by people more capable than them,\nbugs happen. Implementers that use this library are urged to study the code and\nperform a review of their own before using this library in a production system.\n\nIt is also possible to misuse this library in a variety of ways if you don't\nknow what you are doing. If you are ever in doubt, remember that cryptography\nis hard. Leave it to the professionals.\n\n## Background\n\nWhen using a hyperlink to fetch a resource from the Internet, it is often\nuseful to know if the resource has changed since the data was published.\nCryptographic hashes, such as SHA-256, are often used to determine if\npublished data has changed in unexpected ways. Due to the nature of most\nhyperlinks, the cryptographic hash is often published separately from the\nlink itself. The Hashlink specification describes a data model and serialization\nformats for expressing cryptographically protected hyperlinks. The mechanisms\ndescribed in the Hashlink specification enables a system to publish a hyperlink\nin a way that empowers a consuming application to determine if the resource\nassociated with the hyperlink has changed in unexpected ways.\n\nSee also (related specs):\n\n* [IETF Hashlink draft spec](https://tools.ietf.org/html/draft-sporny-hashlink)\n* [IETF Multihash draft spec](https://tools.ietf.org/html/draft-multiformats-multihash)\n* [IETF Multibase draft spec](https://tools.ietf.org/html/draft-multiformats-multibase)\n\n## Install\n\nTo use this library in the browser, you can include the latest version\nvia a simple script tag:\n\n```\n  \u003cscript src=\"https://unpkg.com/hashlink/dist/hashlink.min.js\"\u003e\u003c/script\u003e\n```\n\nTo use the library in Node.js:\n\n- Node.js 8.3+ required.\n\nTo install locally (for development):\n\n```\ngit clone https://github.com/digitalbazaar/hashlink.git\ncd hashlink\nnpm install\n```\n\n## Usage\n\nUse on the command line, or see the API section below.\n\n### Encoding a Hashlink\n\nThere are a number of ways you can encode a hashlink. The simplest way is to\nprovide the data directly.\n\n```bash\n./bin/hl encode hw.txt\n```\n\nYou can encode a hashlink from any data published on the Web:\n\n```bash\n./bin/hl encode --url \"https://example.com/hw.txt\"\n```\n\nYou can also encode a hashlink from data on disk and specify the location on\nthe web that the data will be published to:\n\n```bash\n./bin/hl encode --url \"https://example.com/hw.txt\" hw.txt\n```\n\nHashlinks are also backwards compatible with legacy URL schemes, which enables\nyou to use query parameters to encode the hashlink information:\n\n```bash\n./bin/hl encode --legacy --url \"https://example.com/hw.txt\" hw.txt\n```\n\n### Decoding a Hashlink\n\nTo decode a hashlink, you can run the following command:\n\n```base\n./bin/hl decode hl:zm9YZpCjPLPJ4Epc:z3TSgXTuaHxY2tsArhUreJ4ixgw9NW7DYuQ9QTPQyLHy\n```\n\nThe command above will result in the following output:\n\n```\nURLs: https://example.com/hw.txt\nsha256sum: 12207f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069\n```\n\n### Verifying a Hashlink\n\nTo verify a hashlink, you can run the following command:\n\n```\n./bin/hl verify --file hw.txt hl:zQmNbCYUrvaVfy6w9b5W3SVTP2newPK5FoeY37QurUEUydH\n```\n\nThe command above will result in the following output:\n\n```\nhashlink is valid\n```\n\n## API\n\nThe API is useful when integrating this library with a larger software system.\n\nYou can use the API in the browser by including the latest version\nvia a simple script tag:\n\n```\n  \u003cscript src=\"https://unpkg.com/hashlink/dist/hashlink.min.js\"\u003e\u003c/script\u003e\n```\n\nThe rest of the examples in this section assume a node.js environment, but\nall API calls listed below are also available in the browser version.\n\n### Encoding a Hashlink\n\nYou can encode a hashlink from an existing URL (**coming soon**):\n\n```js\nconst hl = require('hashlink');\n\nconst url = 'https://example.com/hw.txt';\n\n// encode a hashlink by fetching the URL content and hashing it\nconst hlUrl = await hl.encode({url});\n\n// print out the hashlink\nconsole.log(hlUrl);\n```\n\nYou can encode a hashlink from data:\n\n```js\nconst hl = require('hashlink');\n\n// encode a hashlink using data to be published at a URL\nconst data = fs.readFileSync('hw.txt');\nconst url = 'https://example.com/hw.txt';\nconst hlUrl = await hl.encode({data, url});\n\n// print out the hashlink\nconsole.log(hlUrl);\n```\n\nYou can change the default options used by the hashlink function:\n\n```js\nconst {Hashlink} = require('hashlink');\nconst {Urdna2015} = require('hashlink-jsonld');\n\n// setup hl library to use RDF Dataset Canonicalization codec\nconst hl = new Hashlink();\nhl.use(new Urdna2015());\n\n// encode a hashlink using canonicalized data published at a URL\nconst url = 'https://example.com/credential.jsonld';\n// encode the input data using urdna2015 canonicalization algorithm and\n// then hash using blake2b with a 64-bit output\nconst codecs = ['urdna2015', 'blake2b-64'];\nconst hlUrl = await hl.encode({\n  url,\n  codecs,\n  'content-type': 'application/ld+json'\n});\n\n// print out the hashlink\nconsole.log(hlUrl);\n```\n\n### Decoding a Hashlink\n\nYou can decode a hashlink by simply calling decode (**coming soon**):\n\n```js\nconst hl = require('hashlink');\n\nconst url = 'hl:zm9YZpCjPLPJ4Epc:z3TSgXTuaHxY2tsArhUreJ4ixgw9NW7DYuQ9QTPQyLHy';\nconst hlData = hl.decode(url);\n\n// print out the decoded hashlink information (an object)\nconsole.log(hlData);\n```\n\n### Verifying a Hashlink\n\nYou can verify the integrity of a hashlink:\n\n```js\nconst hl = require('hashlink');\n\nconst hashlink = 'hl:zm9YZpCjPLPJ4Epc:z3TSgXTuaHxY2tsArhUreJ4ixgw9NW7DYuQ9QTPQyLHy';\nconst data = '...';\nconst valid = await hl.verify({hashlink, data});\n\n// print out whether or not the hashlink is valid\nconsole.log(valid);\n```\n\n### Advanced Verification\n\nIn some cases, you need to be able to canonize the contents of the hashlink\nin order to verify it:\n\n```js\nconst {Hashlink} = require('hashlink');\nconst {Urdna2016} = require('hashlink-jsonld');\n\n// setup hl library to use RDF Dataset Canonicalization codec\nconst hl = new Hashlink();\nhl.use(new Urdna2015());\n\n// encode a hashlink using canonicalized data published at a URL\nconst hlUrl = 'hl:zQmWvQxTqbG2Z9HPJgG57jjwR154cKhbtJenbyYTWkjgF3e:' +\n  'zuh8iaLobXC8g9tfma1CSTtYBakXeSTkHrYA5hmD4F7dCLw8XYwZ1GWyJ3zwF';\nconst valid = await hl.verify({hashlink: hlUrl});\n\n// print out whether or not the hashlink is valid\nconsole.log(valid);\n```\n### Extending the Hashlink Library\n\nThe Hashlink library is built to support arbitrary transformations of\ninput data using codecs (encoder/decoders).\n\nThe Hashlink library has an internal default instance of a Hashlink\nclass that is provided as a convenience so that for most use cases, the\ndefaults work just fine.\n\n```js\nconst hl = require('hashlink');\nconst hlUrl = await hl.encode({url: 'https://example.com/hw.txt'});\n```\n\nIn some cases, however, a developer will need to extend the default\ntransformations, like when input needs to be canonicalized before it is\nhashed.\n\n```js\nconst {Hashlink} = require('hashlink');\nconst jsonld = require('jsonld');\n\n// setup URDNA2015 codec that encodes\nclass Urdna2015 {\n  constructor() {\n    this.algorithm = 'urdna2015';\n  }\n\n  async encode(input) {\n    const inputJsonld = JSON.parse(new TextDecoder().decode(input));\n    return await jsonld.canonize(\n      inputJsonld, {format: 'application/n-quads'});\n  }\n}\n\n// setup hl library to use RDF Dataset Canonicalization\nconst hl = new Hashlink();\nhl.use(new Urdna2015());\n\n// encode a hashlink using canonicalized data published at a URL\nconst url = 'https://example.com/credential.jsonld';\n\n// encode the input data using urdna2015 canonicalization algorithm and\n// then hash using blake2b with a 64-bit output\nconst codecs = ['urdna2015', 'blake2b-64'];\nconst hlUrl = await hl.encode({\n  url,\n  codecs,\n  'content-type': 'application/ld+json'\n});\n\n// print out the hashlink\nconsole.log(hlUrl);\n```\n\nNote the use of the `Hashlink` class above as well as the `use()` API. Using\nthis API, any arbitrary number of transforms may be applied to the input\ndata before the final hashlink value is produced.\n\n## Testing\n\nTo run Mocha tests:\n\n```\nnpm run mocha\n```\n\nTo run the VC Test Suite:\n\n```\nnpm run fetch-hl-test-suite\nnpm test\n```\n\n## Contribute\n\nSee [the contribute file](https://github.com/digitalbazaar/bedrock/blob/master/CONTRIBUTING.md)!\n\nPRs accepted.\n\nSmall note: If editing the Readme, please conform to the\n[standard-readme](https://github.com/RichardLitt/standard-readme) specification.\n\n## Commercial Support\n\nCommercial support for this library is available upon request from\nDigital Bazaar: support@digitalbazaar.com\n\n## License\n\n[New BSD License (3-clause)](LICENSE) © Digital Bazaar\n\n## Acknowledgements\n\nThe authors of this package thank Daniel Levett\n([dlevs](https://github.com/dlevs/)) for contributing the `hashlink` npm package\nname for use with this project.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdigitalbazaar%2Fhashlink","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdigitalbazaar%2Fhashlink","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdigitalbazaar%2Fhashlink/lists"}