Compare commits
40 Commits
Author | SHA1 | Date | |
---|---|---|---|
00fed871fa | |||
d2efaccaa7 | |||
57e08265dc | |||
23ad99d0e2 | |||
0bae2d6eec | |||
df0f761bdb | |||
49f990ec2a | |||
1078af0889 | |||
feb83abd33 | |||
87a64c361c | |||
4fa410a3bd | |||
ca447ded30 | |||
777ed7575c | |||
a78e3e3362 | |||
b8e91e9bf8 | |||
f6630f065d | |||
bc8bf48679 | |||
ef06e465cb | |||
e3eca5528d | |||
d43f568795 | |||
85f2cc4745 | |||
143eef8781 | |||
bb7bee3b42 | |||
50197d4634 | |||
2e7a61541f | |||
5a6ae2f083 | |||
bf1b89a95a | |||
3e2b300cdb | |||
d865e3b874 | |||
13f1f854ce | |||
34586b5fec | |||
edb13cbdcf | |||
5c2e01fe84 | |||
d348590e9a | |||
c908cd824b | |||
4a62342015 | |||
0a9a0d3e90 | |||
8d5238e23e | |||
9e5ce63c24 | |||
3921cbc8f8 |
66
.gitea/workflows/default_nottags.yaml
Normal file
66
.gitea/workflows/default_nottags.yaml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
name: Default (not tags)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags-ignore:
|
||||||
|
- '**'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
|
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
||||||
|
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||||
|
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||||
|
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||||
|
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
security:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install pnpm and npmci
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
|
||||||
|
- name: Run npm prepare
|
||||||
|
run: npmci npm prepare
|
||||||
|
|
||||||
|
- name: Audit production dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --prod
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Audit development dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --dev
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
test:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: security
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Test stable
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm test
|
||||||
|
|
||||||
|
- name: Test build
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm build
|
124
.gitea/workflows/default_tags.yaml
Normal file
124
.gitea/workflows/default_tags.yaml
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
name: Default (tags)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
|
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
||||||
|
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||||
|
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||||
|
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||||
|
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
security:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Audit production dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --prod
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Audit development dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --dev
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
test:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: security
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Test stable
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm test
|
||||||
|
|
||||||
|
- name: Test build
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm build
|
||||||
|
|
||||||
|
release:
|
||||||
|
needs: test
|
||||||
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm publish
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
needs: test
|
||||||
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Code quality
|
||||||
|
run: |
|
||||||
|
npmci command npm install -g typescript
|
||||||
|
npmci npm install
|
||||||
|
|
||||||
|
- name: Trigger
|
||||||
|
run: npmci trigger
|
||||||
|
|
||||||
|
- name: Build docs and upload artifacts
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
pnpm install -g @gitzone/tsdoc
|
||||||
|
npmci command tsdoc
|
||||||
|
continue-on-error: true
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -15,8 +15,6 @@ node_modules/
|
|||||||
|
|
||||||
# builds
|
# builds
|
||||||
dist/
|
dist/
|
||||||
dist_web/
|
dist_*/
|
||||||
dist_serve/
|
|
||||||
dist_ts_web/
|
|
||||||
|
|
||||||
# custom
|
# custom
|
126
.gitlab-ci.yml
126
.gitlab-ci.yml
@ -1,126 +0,0 @@
|
|||||||
# gitzone ci_default
|
|
||||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
|
||||||
|
|
||||||
cache:
|
|
||||||
paths:
|
|
||||||
- .npmci_cache/
|
|
||||||
key: '$CI_BUILD_STAGE'
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- security
|
|
||||||
- test
|
|
||||||
- release
|
|
||||||
- metadata
|
|
||||||
|
|
||||||
# ====================
|
|
||||||
# security stage
|
|
||||||
# ====================
|
|
||||||
mirror:
|
|
||||||
stage: security
|
|
||||||
script:
|
|
||||||
- npmci git mirror
|
|
||||||
tags:
|
|
||||||
- lossless
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
snyk:
|
|
||||||
image: registry.gitlab.com/hosttoday/ht-docker-node:snyk
|
|
||||||
stage: security
|
|
||||||
script:
|
|
||||||
- npmci npm prepare
|
|
||||||
- npmci command npm install --ignore-scripts
|
|
||||||
- npmci command snyk test
|
|
||||||
tags:
|
|
||||||
- lossless
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
# ====================
|
|
||||||
# test stage
|
|
||||||
# ====================
|
|
||||||
|
|
||||||
testStable:
|
|
||||||
stage: test
|
|
||||||
script:
|
|
||||||
- npmci npm prepare
|
|
||||||
- npmci node install stable
|
|
||||||
- npmci npm install
|
|
||||||
- npmci npm test
|
|
||||||
coverage: /\d+.?\d+?\%\s*coverage/
|
|
||||||
tags:
|
|
||||||
- lossless
|
|
||||||
- docker
|
|
||||||
- priv
|
|
||||||
|
|
||||||
testBuild:
|
|
||||||
stage: test
|
|
||||||
script:
|
|
||||||
- npmci npm prepare
|
|
||||||
- npmci node install stable
|
|
||||||
- npmci npm install
|
|
||||||
- npmci command npm run build
|
|
||||||
coverage: /\d+.?\d+?\%\s*coverage/
|
|
||||||
tags:
|
|
||||||
- lossless
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
release:
|
|
||||||
stage: release
|
|
||||||
script:
|
|
||||||
- npmci node install stable
|
|
||||||
- npmci npm publish
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
tags:
|
|
||||||
- lossless
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
# ====================
|
|
||||||
# metadata stage
|
|
||||||
# ====================
|
|
||||||
codequality:
|
|
||||||
stage: metadata
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- npmci command npm install -g tslint typescript
|
|
||||||
- npmci npm prepare
|
|
||||||
- npmci npm install
|
|
||||||
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
|
|
||||||
tags:
|
|
||||||
- lossless
|
|
||||||
- docker
|
|
||||||
- priv
|
|
||||||
|
|
||||||
trigger:
|
|
||||||
stage: metadata
|
|
||||||
script:
|
|
||||||
- npmci trigger
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
tags:
|
|
||||||
- lossless
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
pages:
|
|
||||||
stage: metadata
|
|
||||||
script:
|
|
||||||
- npmci node install lts
|
|
||||||
- npmci command npm install -g @gitzone/tsdoc
|
|
||||||
- npmci npm prepare
|
|
||||||
- npmci npm install
|
|
||||||
- npmci command tsdoc
|
|
||||||
tags:
|
|
||||||
- lossless
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
artifacts:
|
|
||||||
expire_in: 1 week
|
|
||||||
paths:
|
|
||||||
- public
|
|
||||||
allow_failure: true
|
|
4
.snyk
4
.snyk
@ -1,4 +0,0 @@
|
|||||||
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
|
|
||||||
version: v1.13.3
|
|
||||||
ignore: {}
|
|
||||||
patch: {}
|
|
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"command": "npm test",
|
||||||
|
"name": "Run npm test",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "node-terminal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"json.schemas": [
|
||||||
|
{
|
||||||
|
"fileMatch": ["/npmextra.json"],
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"npmci": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "settings for npmci"
|
||||||
|
},
|
||||||
|
"gitzone": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "settings for gitzone",
|
||||||
|
"properties": {
|
||||||
|
"projectType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
80
changelog.md
Normal file
80
changelog.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-06-19 - 3.2.0 - feat(package)
|
||||||
|
Update package.json to use exports field for dual entry points
|
||||||
|
|
||||||
|
- Replaced the main and typings fields with an exports object that supports both default and web entry points
|
||||||
|
- Ensures consistency in module resolution between Node.js and browser environments
|
||||||
|
|
||||||
|
## 2025-06-19 - 3.1.0 - feat(browser)
|
||||||
|
Implement fallback SHA256 for non-HTTPS environments and enhance browser tests for consistent hashing
|
||||||
|
|
||||||
|
- Added a pure JavaScript SHA256 fallback in ts_web/sha256.fallback.ts for environments without crypto.subtle
|
||||||
|
- Updated ts_web/index.ts to use the fallback when necessary
|
||||||
|
- Enhanced browser tests in test/test.browser.ts to verify consistent hash outputs
|
||||||
|
- Reflected new features in documentation updates (readme.plan.md)
|
||||||
|
|
||||||
|
## 2025-06-19 - 3.0.4 - feat
|
||||||
|
Merge isohash functionality into smarthash to enable cross‐environment hash support. This release introduces browser‐compatible SHA256 functions via the Web Crypto API and plugins for environment detection and JSON handling.
|
||||||
|
|
||||||
|
- Added new plan and implementation steps to merge isohash into smarthash.
|
||||||
|
- Updated test files to use the new tapbundle import.
|
||||||
|
- Implemented browser‐specific hashing functions in ts_web/index.ts and ts_web/plugins.ts.
|
||||||
|
- Created browser tests in test/test.browser.ts for SHA256 functions.
|
||||||
|
- Ensured consistent smarthash functionality across environments.
|
||||||
|
|
||||||
|
Note: Several non–breaking maintenance updates (e.g. description, tsconfig, and npmextra.json adjustments) were applied between 2024 and 2023 alongside version marker commits.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2023-09-22 to 2022-06-26 - 3.0.0 - Maintenance
|
||||||
|
Between versions 3.0.3 and 3.0.0, a series of core fixes and organizational improvements were rolled out.
|
||||||
|
|
||||||
|
- Multiple “fix(core)” commits addressed various update needs.
|
||||||
|
- A couple of releases also switched to a new organization scheme.
|
||||||
|
- Routine maintenance commits ensured stability across these versions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2022-06-26 - 2.1.10 - BREAKING CHANGE
|
||||||
|
A major change was introduced by switching the module system.
|
||||||
|
|
||||||
|
- BREAKING CHANGE(core): Switched to ESM, requiring consumers to update their imports accordingly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2021-03-01 to 2019-11-21 - 2.1.0 - Maintenance
|
||||||
|
Across versions 2.1.9 down to 2.1.0, the project received multiple fixes and CI updates.
|
||||||
|
|
||||||
|
- Repeated “fix(core)” commits improved internal stability.
|
||||||
|
- A “fix(ci)” update was also introduced to streamline continuous integration processes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2019-11-21 - 2.0.6 - feat
|
||||||
|
New functionality was added to expand the available hashing algorithms.
|
||||||
|
|
||||||
|
- feat(md5): Now creates MD5 hashes, broadening the project’s cryptographic capabilities.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2019-07-04 to 2018-09-07 - 2.0.0 - Maintenance
|
||||||
|
This range of releases was dedicated to refining core functionality and enhancing security.
|
||||||
|
|
||||||
|
- Numerous “fix(core)” commits ensured consistent behavior.
|
||||||
|
- A “fix(snyk)” commit added a .snyk file and marked the project as Open Source for improved security auditing.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2018-09-07 - 1.0.4 - BREAKING CHANGE
|
||||||
|
A breaking change was introduced by renaming the package scope.
|
||||||
|
|
||||||
|
- BREAKING CHANGE(scope): Changed the package name to @pushrocks/smarthash, requiring updates for consumers referencing the old name.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2016-08-16 to 2016-05-23 - 1.0.0 - Initial Setup
|
||||||
|
During the early days of the project, core implementation and structure were established.
|
||||||
|
|
||||||
|
- Early commits included the initial implementation (“implementation is ready”), package metadata adjustments (e.g. “update package tags”, “fix README”), and structural additions (“add structure”).
|
||||||
|
- The journey began with the Initial commit on 2016-05-23, setting the groundwork for future development.
|
@ -1,15 +1,36 @@
|
|||||||
{
|
{
|
||||||
"gitzone": {
|
"gitzone": {
|
||||||
|
"projectType": "npm",
|
||||||
"module": {
|
"module": {
|
||||||
"githost": "gitlab.com",
|
"githost": "code.foss.global",
|
||||||
"gitscope": "pushrocks",
|
"gitscope": "push.rocks",
|
||||||
"gitrepo": "smarthash",
|
"gitrepo": "smarthash",
|
||||||
"shortDescription": "simplifies access to node hash functions",
|
"description": "Cross-environment hash functions (SHA256 and MD5) for Node.js and browsers, with support for strings, streams, and files.",
|
||||||
"npmPackagename": "@pushrocks/smarthash",
|
"npmPackagename": "@push.rocks/smarthash",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"crypto",
|
||||||
|
"hashing",
|
||||||
|
"SHA256",
|
||||||
|
"MD5",
|
||||||
|
"security",
|
||||||
|
"node.js",
|
||||||
|
"browser",
|
||||||
|
"cross-environment",
|
||||||
|
"web crypto",
|
||||||
|
"stream hashing",
|
||||||
|
"file hashing",
|
||||||
|
"synchronous hashing",
|
||||||
|
"asynchronous hashing",
|
||||||
|
"data integrity",
|
||||||
|
"typescript"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"npmci": {
|
"npmci": {
|
||||||
"npmAccessLevel": "public"
|
"npmAccessLevel": "public"
|
||||||
|
},
|
||||||
|
"tsdoc": {
|
||||||
|
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
1728
package-lock.json
generated
1728
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
82
package.json
82
package.json
@ -1,57 +1,69 @@
|
|||||||
{
|
{
|
||||||
"name": "@pushrocks/smarthash",
|
"name": "@push.rocks/smarthash",
|
||||||
"version": "2.1.1",
|
"version": "3.2.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "simplified access to node hash functions",
|
"description": "Cross-environment hash functions (SHA256 and MD5) for Node.js and browsers, with support for strings, streams, and files.",
|
||||||
"main": "dist/index.js",
|
"exports": {
|
||||||
"typings": "dist/index.d.ts",
|
".": "./dist_ts/index.js",
|
||||||
"scripts": {
|
"./web": "./dist_ts_web/index.js"
|
||||||
"test": "(tstest test/)",
|
|
||||||
"build": "(tsbuild)"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"scripts": {
|
||||||
"type": "git",
|
"test": "(tstest test/ --web)",
|
||||||
"url": "git+https://github.com/pushrocks/nodehash.git"
|
"build": "(tsbuild tsfolders --allowimplicitany)",
|
||||||
|
"buildDocs": "tsdoc"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"pushrocks",
|
"crypto",
|
||||||
"typescript",
|
"hashing",
|
||||||
"hash",
|
"SHA256",
|
||||||
"node",
|
"MD5",
|
||||||
"sha256",
|
"security",
|
||||||
"stream",
|
"node.js",
|
||||||
"filehash"
|
"browser",
|
||||||
|
"cross-environment",
|
||||||
|
"web crypto",
|
||||||
|
"stream hashing",
|
||||||
|
"file hashing",
|
||||||
|
"synchronous hashing",
|
||||||
|
"asynchronous hashing",
|
||||||
|
"data integrity",
|
||||||
|
"typescript"
|
||||||
],
|
],
|
||||||
"author": "Lossless GmbH",
|
"author": "Lossless GmbH",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/pushrocks/nodehash/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/pushrocks/nodehash#readme",
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@gitzone/tsbuild": "^2.1.17",
|
"@git.zone/tsbuild": "^2.1.70",
|
||||||
"@gitzone/tsrun": "^1.2.8",
|
"@git.zone/tsrun": "^1.2.46",
|
||||||
"@gitzone/tstest": "^1.0.28",
|
"@git.zone/tstest": "^1.0.81",
|
||||||
"@pushrocks/tapbundle": "^3.2.0",
|
"@types/node": "^20.6.3"
|
||||||
"@types/node": "^12.12.11",
|
|
||||||
"tslint": "^5.20.1",
|
|
||||||
"tslint-config-prettier": "^1.18.0"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@pushrocks/smartjson": "^3.0.8",
|
"@push.rocks/smartenv": "^5.0.5",
|
||||||
"@pushrocks/smartpromise": "^3.0.6",
|
"@push.rocks/smartjson": "^5.0.10",
|
||||||
"@types/through2": "^2.0.34",
|
"@push.rocks/smartpromise": "^4.0.3",
|
||||||
"through2": "^3.0.1"
|
"@types/through2": "^2.0.39",
|
||||||
|
"through2": "^4.0.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"ts/**/*",
|
"ts/**/*",
|
||||||
"ts_web/**/*",
|
"ts_web/**/*",
|
||||||
"dist/**/*",
|
"dist/**/*",
|
||||||
"dist_web/**/*",
|
"dist_*/**/*",
|
||||||
|
"dist_ts/**/*",
|
||||||
"dist_ts_web/**/*",
|
"dist_ts_web/**/*",
|
||||||
"assets/**/*",
|
"assets/**/*",
|
||||||
"cli.js",
|
"cli.js",
|
||||||
"npmextra.json",
|
"npmextra.json",
|
||||||
"readme.md"
|
"readme.md"
|
||||||
]
|
],
|
||||||
|
"browserslist": [
|
||||||
|
"last 1 chrome versions"
|
||||||
|
],
|
||||||
|
"type": "module",
|
||||||
|
"homepage": "https://code.foss.global/push.rocks/smarthash",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://code.foss.global/push.rocks/smarthash.git"
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
|
||||||
}
|
}
|
||||||
|
8881
pnpm-lock.yaml
generated
Normal file
8881
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
1
readme.hints.md
Normal file
1
readme.hints.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
135
readme.md
Normal file
135
readme.md
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
# @push.rocks/smarthash
|
||||||
|
simplified access to node hash functions
|
||||||
|
|
||||||
|
## Install
|
||||||
|
To install `@push.rocks/smarthash`, use the following command with npm:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @push.rocks/smarthash --save
|
||||||
|
```
|
||||||
|
|
||||||
|
This will add `@push.rocks/smarthash` to your project's dependencies.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
The `@push.rocks/smarthash` library provides a simplified interface to Node.js hash functions, including utilities for hashing strings, files, and streams with popular algorithms like SHA-256 and MD5. Below are detailed examples to demonstrate the capabilities and usage of this library using ESM syntax and TypeScript.
|
||||||
|
|
||||||
|
### Hashing Strings
|
||||||
|
#### SHA-256
|
||||||
|
```typescript
|
||||||
|
import { sha256FromString, sha256FromStringSync } from '@push.rocks/smarthash';
|
||||||
|
|
||||||
|
// Asynchronously hash a string
|
||||||
|
const asyncHash = async () => {
|
||||||
|
const hash = await sha256FromString('Hello, world!');
|
||||||
|
console.log(hash); // Output the hashed string
|
||||||
|
};
|
||||||
|
asyncHash();
|
||||||
|
|
||||||
|
// Synchronously hash a string
|
||||||
|
const syncHash = sha256FromStringSync('Hello, world!');
|
||||||
|
console.log(syncHash); // Output the hashed string
|
||||||
|
```
|
||||||
|
|
||||||
|
#### MD5
|
||||||
|
```typescript
|
||||||
|
import { md5FromString } from '@push.rocks/smarthash';
|
||||||
|
|
||||||
|
// Asynchronously hash a string with MD5
|
||||||
|
const md5Hash = async () => {
|
||||||
|
const hash = await md5FromString('Hello, world!');
|
||||||
|
console.log(hash); // Output the MD5 hash
|
||||||
|
};
|
||||||
|
md5Hash();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hashing Files
|
||||||
|
To hash a file, you can use the `sha256FromFile` function. It reads the file specified by the path and calculates the SHA-256 hash.
|
||||||
|
```typescript
|
||||||
|
import { sha256FromFile } from '@push.rocks/smarthash';
|
||||||
|
|
||||||
|
// Asynchronously hash a file
|
||||||
|
const hashFile = async () => {
|
||||||
|
const fileHash = await sha256FromFile('./path/to/your/file.txt');
|
||||||
|
console.log(fileHash); // Output the file's hash
|
||||||
|
};
|
||||||
|
hashFile();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hashing Streams
|
||||||
|
`@push.rocks/smarthash` also allows for hashing of streams, which is particularly useful for large files or data streams.
|
||||||
|
```typescript
|
||||||
|
import { sha256FromStream } from '@push.rocks/smarthash';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
// Create a read stream from a file
|
||||||
|
const readStream = fs.createReadStream('./path/to/your/largeFile.txt');
|
||||||
|
|
||||||
|
// Asynchronously hash the stream
|
||||||
|
const hashStream = async () => {
|
||||||
|
const streamHash = await sha256FromStream(readStream);
|
||||||
|
console.log(streamHash); // Output the hash of the stream's content
|
||||||
|
};
|
||||||
|
hashStream();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Advanced Usage
|
||||||
|
#### Hashing Objects
|
||||||
|
For hashing JavaScript objects, you can serialize them and hash the resulting string. This is useful for creating hashes from complex data structures.
|
||||||
|
```typescript
|
||||||
|
import { sha265FromObject } from '@push.rocks/smarthash';
|
||||||
|
|
||||||
|
// Hash a JavaScript object
|
||||||
|
const hashObject = async () => {
|
||||||
|
const object = { hello: 'world', number: 42 };
|
||||||
|
const objectHash = await sha265FromObject(object);
|
||||||
|
console.log(objectHash); // Output the hash of the object
|
||||||
|
};
|
||||||
|
hashObject();
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Error Handling
|
||||||
|
All asynchronous functions return promises, so you can use `.catch()` for error handling or try-catch blocks within async functions.
|
||||||
|
```typescript
|
||||||
|
import { sha256FromString } from '@push.rocks/smarthash';
|
||||||
|
|
||||||
|
// Using .catch() for promises
|
||||||
|
sha256FromString('test')
|
||||||
|
.then(hash => console.log(hash))
|
||||||
|
.catch(error => console.error(error));
|
||||||
|
|
||||||
|
// Using try-catch with async functions
|
||||||
|
const getHash = async () => {
|
||||||
|
try {
|
||||||
|
const hash = await sha256FromString('test');
|
||||||
|
console.log(hash);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
getHash();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
- Utilize asynchronous functions for hashing large files or streams to avoid blocking the main thread.
|
||||||
|
- For hashing sensitive information, ensure to follow security best practices, including using up-to-date algorithms and managing secrets properly.
|
||||||
|
|
||||||
|
By leveraging `@push.rocks/smarthash`, developers can easily integrate hashing functionalities into their Node.js applications, benefiting from its simplified API and TypeScript support for better development experience.
|
||||||
|
|
||||||
|
## License and Legal Information
|
||||||
|
|
||||||
|
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||||
|
|
||||||
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
### Trademarks
|
||||||
|
|
||||||
|
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||||
|
|
||||||
|
### Company Information
|
||||||
|
|
||||||
|
Task Venture Capital GmbH
|
||||||
|
Registered at District court Bremen HRB 35230 HB, Germany
|
||||||
|
|
||||||
|
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||||
|
|
||||||
|
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
45
readme.plan.md
Normal file
45
readme.plan.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Merge Plan: isohash into smarthash
|
||||||
|
|
||||||
|
**First line: Command to reread CLAUDE.md**: `cat ~/.claude/CLAUDE.md`
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
Merge the functionality from @push.rocks/isohash into @push.rocks/smarthash to provide cross-environment hash support (browser and Node.js).
|
||||||
|
|
||||||
|
## Implementation Steps
|
||||||
|
|
||||||
|
### 1. Create ts_web directory structure ✓
|
||||||
|
- Create `./ts_web` directory for browser-specific code
|
||||||
|
- This will house the Web Crypto API implementation
|
||||||
|
|
||||||
|
### 2. Add required dependencies ✓
|
||||||
|
- Add `@push.rocks/smartenv` to package.json dependencies
|
||||||
|
- This is needed for environment detection
|
||||||
|
|
||||||
|
### 3. Create web-specific plugin file ✓
|
||||||
|
- Create `ts_web/plugins.ts` with smartenv import
|
||||||
|
- Follow the plugins pattern used in the Node.js version
|
||||||
|
|
||||||
|
### 4. Implement browser-compatible hash functions ✓
|
||||||
|
- Copy and adapt `index.ts` from isohash to `ts_web/index.ts`
|
||||||
|
- Remove circular dependency (isohash importing smarthash)
|
||||||
|
- Use native Web Crypto API for SHA256 in browser
|
||||||
|
- Maintain compatibility with existing smarthash API
|
||||||
|
|
||||||
|
### 5. Build and verify ✓
|
||||||
|
- Run `pnpm build` to ensure TypeScript compilation succeeds
|
||||||
|
- Check that both Node.js and browser builds are created
|
||||||
|
|
||||||
|
### 6. Test functionality ✓
|
||||||
|
- Run `pnpm test` to ensure all tests pass
|
||||||
|
- Verify browser compatibility through web tests
|
||||||
|
|
||||||
|
## Key Considerations
|
||||||
|
- The web version uses native Web Crypto API for performance
|
||||||
|
- The Node.js version continues using the existing crypto implementation
|
||||||
|
- API remains consistent across both environments
|
||||||
|
- No breaking changes to existing smarthash functionality
|
||||||
|
|
||||||
|
## Additional Features Implemented
|
||||||
|
- **Fallback for non-HTTPS environments**: Added pure JavaScript SHA256 implementation that automatically activates when crypto.subtle is not available (e.g., HTTP or file:// protocols)
|
||||||
|
- **Comprehensive browser tests**: Created test.browser.ts with specific browser environment tests
|
||||||
|
- **Cross-environment consistency**: Ensured hash outputs match across Node.js and browser implementations
|
77
test/test.browser.ts
Normal file
77
test/test.browser.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||||
|
import * as smarthash from '../ts_web/index.js';
|
||||||
|
|
||||||
|
tap.test('sha256FromString should work in browser environment', async () => {
|
||||||
|
const testHash = await smarthash.sha256FromString('test');
|
||||||
|
const testHash2 = await smarthash.sha256FromString('testString');
|
||||||
|
const testHash3 = await smarthash.sha256FromString('test');
|
||||||
|
|
||||||
|
expect(testHash).toEqual(testHash3);
|
||||||
|
expect(testHash).not.toEqual(testHash2);
|
||||||
|
expect(testHash).toBeTypeofString();
|
||||||
|
expect(testHash).toHaveLength(64); // SHA256 hash is 64 hex characters
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('sha256FromBuffer should work with Uint8Array in browser', async () => {
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const buffer = encoder.encode('test');
|
||||||
|
|
||||||
|
const hashFromBuffer = await smarthash.sha256FromBuffer(buffer);
|
||||||
|
const hashFromString = await smarthash.sha256FromString('test');
|
||||||
|
|
||||||
|
expect(hashFromBuffer).toEqual(hashFromString);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('sha265FromObject should produce reproducible hashes', async () => {
|
||||||
|
const hash1 = await smarthash.sha265FromObject({
|
||||||
|
hithere: 1,
|
||||||
|
wow: 'two',
|
||||||
|
});
|
||||||
|
|
||||||
|
const hash2 = await smarthash.sha265FromObject({
|
||||||
|
wow: 'two',
|
||||||
|
hithere: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
const hash3 = await smarthash.sha265FromObject({
|
||||||
|
wow: 'twoe',
|
||||||
|
hithere: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(hash1).toEqual(hash2);
|
||||||
|
expect(hash1).not.toEqual(hash3);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('sha256FromStringSync should throw in browser environment', async () => {
|
||||||
|
expect(() => {
|
||||||
|
smarthash.sha256FromStringSync('test');
|
||||||
|
}).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('sha256FromStream should throw in browser environment', async () => {
|
||||||
|
expect(() => {
|
||||||
|
smarthash.sha256FromStream(null);
|
||||||
|
}).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('sha256FromFile should throw in browser environment', async () => {
|
||||||
|
await expect(smarthash.sha256FromFile('./test.txt')).rejects.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('md5FromString should throw in browser environment', async () => {
|
||||||
|
await expect(smarthash.md5FromString('test')).rejects.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('sha256 produces consistent results across environments', async () => {
|
||||||
|
// Test that our implementation produces the same hash as Node.js crypto
|
||||||
|
const testHash = await smarthash.sha256FromString('test');
|
||||||
|
const expectedHash = '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08';
|
||||||
|
expect(testHash).toEqual(expectedHash);
|
||||||
|
|
||||||
|
// Test with different string
|
||||||
|
const testHash2 = await smarthash.sha256FromString('hello world');
|
||||||
|
const expectedHash2 = 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9';
|
||||||
|
expect(testHash2).toEqual(expectedHash2);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default tap.start();
|
32
test/test.ts
32
test/test.ts
@ -1,55 +1,55 @@
|
|||||||
import { tap, expect } from '@pushrocks/tapbundle';
|
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||||
import fs = require('fs');
|
import * as fs from 'fs';
|
||||||
|
|
||||||
import * as smarthash from '../ts/index';
|
import * as smarthash from '../ts/index.js';
|
||||||
|
|
||||||
tap.test('sha256FromStringSync should convert a String to sha256 hash synchronously', async () => {
|
tap.test('sha256FromStringSync should convert a String to sha256 hash synchronously', async () => {
|
||||||
const testHash = smarthash.sha256FromStringSync('test');
|
const testHash = smarthash.sha256FromStringSync('test');
|
||||||
const testHash2 = smarthash.sha256FromStringSync('testString');
|
const testHash2 = smarthash.sha256FromStringSync('testString');
|
||||||
const testHash3 = smarthash.sha256FromStringSync('test');
|
const testHash3 = smarthash.sha256FromStringSync('test');
|
||||||
expect(testHash).to.equal(testHash3);
|
expect(testHash).toEqual(testHash3);
|
||||||
expect(testHash).to.not.equal('test');
|
expect(testHash).not.toEqual('test');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('sha256fromStringSync should convert a String to sha256 hash synchronously', async () => {
|
tap.test('sha256fromStringSync should convert a String to sha256 hash synchronously', async () => {
|
||||||
const resultString = await smarthash.sha256FromString('test');
|
const resultString = await smarthash.sha256FromString('test');
|
||||||
const compareString = smarthash.sha256FromStringSync('test');
|
const compareString = smarthash.sha256FromStringSync('test');
|
||||||
expect(resultString).to.equal(compareString);
|
expect(resultString).toEqual(compareString);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('sha256fromStream should convert a Stream to sha256', async tools => {
|
tap.test('sha256fromStream should convert a Stream to sha256', async (tools) => {
|
||||||
const readStream = fs.createReadStream('./test/testImageForHash.jpg');
|
const readStream = fs.createReadStream('./test/testImageForHash.jpg');
|
||||||
const resultString: string = await smarthash.sha256FromStream(readStream);
|
const resultString: string = await smarthash.sha256FromStream(readStream);
|
||||||
expect(resultString).to.equal('45b80413ed93acb495691186ce61850449439f9183352b9bff96d5533fa1046c');
|
expect(resultString).toEqual('45b80413ed93acb495691186ce61850449439f9183352b9bff96d5533fa1046c');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('sha256fromFile should convert a Stream to sha256', async () => {
|
tap.test('sha256fromFile should convert a Stream to sha256', async () => {
|
||||||
const resultString = await smarthash.sha256FromFile('./test/testImageForHash.jpg');
|
const resultString = await smarthash.sha256FromFile('./test/testImageForHash.jpg');
|
||||||
expect(resultString).to.equal('45b80413ed93acb495691186ce61850449439f9183352b9bff96d5533fa1046c');
|
expect(resultString).toEqual('45b80413ed93acb495691186ce61850449439f9183352b9bff96d5533fa1046c');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should produce reproducible hash from Object', async () => {
|
tap.test('should produce reproducible hash from Object', async () => {
|
||||||
const hash1 = await smarthash.sha265FromObject({
|
const hash1 = await smarthash.sha265FromObject({
|
||||||
hithere: 1,
|
hithere: 1,
|
||||||
wow: 'two'
|
wow: 'two',
|
||||||
});
|
});
|
||||||
|
|
||||||
const hash2 = await smarthash.sha265FromObject({
|
const hash2 = await smarthash.sha265FromObject({
|
||||||
wow: 'two',
|
wow: 'two',
|
||||||
hithere: 1
|
hithere: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
const hash3 = await smarthash.sha265FromObject({
|
const hash3 = await smarthash.sha265FromObject({
|
||||||
wow: 'twoe',
|
wow: 'twoe',
|
||||||
hithere: 1
|
hithere: 1,
|
||||||
});
|
});
|
||||||
expect(hash1).to.equal(hash2);
|
expect(hash1).toEqual(hash2);
|
||||||
expect(hash1).to.not.equal(hash3);
|
expect(hash1).not.toEqual(hash3);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should create md5hash from string', async () => {
|
tap.test('should create md5hash from string', async () => {
|
||||||
const md5Hash = await smarthash.md5FromString('hellothere');
|
const md5Hash = await smarthash.md5FromString('hellothere');
|
||||||
expect(md5Hash).to.equal('c6f7c372641dd25e0fddf0215375561f');
|
expect(md5Hash).toEqual('c6f7c372641dd25e0fddf0215375561f');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.start();
|
export default tap.start();
|
||||||
|
8
ts/00_commitinfo_data.ts
Normal file
8
ts/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* autocreated commitinfo by @push.rocks/commitinfo
|
||||||
|
*/
|
||||||
|
export const commitinfo = {
|
||||||
|
name: '@push.rocks/smarthash',
|
||||||
|
version: '3.2.0',
|
||||||
|
description: 'Cross-environment hash functions (SHA256 and MD5) for Node.js and browsers, with support for strings, streams, and files.'
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import * as plugins from './nodehash.plugins';
|
import * as plugins from './nodehash.plugins.js';
|
||||||
|
|
||||||
export * from './nodehash.sha256';
|
export * from './nodehash.sha256.js';
|
||||||
export * from './nodehash.md5';
|
export * from './nodehash.md5.js';
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import * as plugins from './nodehash.plugins';
|
import * as plugins from './nodehash.plugins.js';
|
||||||
|
|
||||||
export const hashStreamPipeStop = resolveFuntion => {
|
export const hashStreamPipeStop = (resolveFunctionArg: (inputArg: string) => any) => {
|
||||||
const forEach = (chunk: Buffer, enc, cb) => {
|
const forEach = (chunk: Buffer, enc: any, cb: any) => {
|
||||||
resolveFuntion(chunk.toString('utf8'));
|
resolveFunctionArg(chunk.toString('utf8'));
|
||||||
cb(null, chunk);
|
cb(null, chunk);
|
||||||
};
|
};
|
||||||
|
|
||||||
const atEnd = cb => {
|
const atEnd = (cb: any) => {
|
||||||
cb();
|
cb();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
import * as plugins from './nodehash.plugins';
|
import * as plugins from './nodehash.plugins.js';
|
||||||
|
|
||||||
export const md5FromString = async (stringToHash: string) => {
|
export const md5FromString = async (stringToHash: string) => {
|
||||||
return plugins.crypto
|
return plugins.crypto.createHash('md5').update(stringToHash).digest('hex');
|
||||||
.createHash('md5')
|
|
||||||
.update(stringToHash)
|
|
||||||
.digest('hex');
|
|
||||||
};
|
};
|
||||||
|
@ -7,8 +7,8 @@ import * as stream from 'stream';
|
|||||||
export { crypto, fs, path, stream };
|
export { crypto, fs, path, stream };
|
||||||
|
|
||||||
// pushrocks scope
|
// pushrocks scope
|
||||||
import * as smartpromise from '@pushrocks/smartpromise';
|
import * as smartpromise from '@push.rocks/smartpromise';
|
||||||
import * as smartjson from '@pushrocks/smartjson';
|
import * as smartjson from '@push.rocks/smartjson';
|
||||||
|
|
||||||
export { smartpromise, smartjson };
|
export { smartpromise, smartjson };
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as plugins from './nodehash.plugins';
|
import * as plugins from './nodehash.plugins.js';
|
||||||
import * as helpers from './nodehash.helpers';
|
import * as helpers from './nodehash.helpers.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates sha256 Hash from Stream
|
* creates sha256 Hash from Stream
|
||||||
@ -26,7 +26,7 @@ export const sha256FromFile = async (filePath: string): Promise<string> => {
|
|||||||
/**
|
/**
|
||||||
* Computes sha256 Hash from String synchronously
|
* Computes sha256 Hash from String synchronously
|
||||||
*/
|
*/
|
||||||
export let sha256FromStringSync = (stringArg): string => {
|
export const sha256FromStringSync = (stringArg: string): string => {
|
||||||
const hash = plugins.crypto.createHash('sha256');
|
const hash = plugins.crypto.createHash('sha256');
|
||||||
hash.update(stringArg);
|
hash.update(stringArg);
|
||||||
return hash.digest('hex');
|
return hash.digest('hex');
|
||||||
@ -42,11 +42,21 @@ export const sha256FromString = async (stringArg: string): Promise<string> => {
|
|||||||
return hashResult;
|
return hashResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes sha256 Hash from String
|
||||||
|
*/
|
||||||
|
export const sha256FromBuffer = async (bufferArg: Buffer): Promise<string> => {
|
||||||
|
const hash = plugins.crypto.createHash('sha256');
|
||||||
|
hash.update(bufferArg);
|
||||||
|
const hashResult = hash.digest('hex');
|
||||||
|
return hashResult;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* computes sha265 Hash from Object
|
* computes sha265 Hash from Object
|
||||||
*/
|
*/
|
||||||
export const sha265FromObject = async (objectArg: any): Promise<string> => {
|
export const sha265FromObject = async (objectArg: any): Promise<string> => {
|
||||||
const stringifiedObject = plugins.smartjson.Smartjson.stringify(objectArg, {});
|
const stringifiedObject = plugins.smartjson.stringify(objectArg);
|
||||||
const hashResult = await sha256FromString(stringifiedObject);
|
const hashResult = await sha256FromString(stringifiedObject);
|
||||||
return hashResult;
|
return hashResult;
|
||||||
};
|
};
|
||||||
|
8
ts_web/00_commitinfo_data.ts
Normal file
8
ts_web/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* autocreated commitinfo by @push.rocks/commitinfo
|
||||||
|
*/
|
||||||
|
export const commitinfo = {
|
||||||
|
name: '@push.rocks/smarthash',
|
||||||
|
version: '3.2.0',
|
||||||
|
description: 'Cross-environment hash functions (SHA256 and MD5) for Node.js and browsers, with support for strings, streams, and files.'
|
||||||
|
}
|
104
ts_web/index.ts
Normal file
104
ts_web/index.ts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import * as plugins from './plugins.js';
|
||||||
|
import { sha256Fallback } from './sha256.fallback.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert ArrayBuffer to hex string
|
||||||
|
*/
|
||||||
|
const hex = (buffer: ArrayBuffer): string => {
|
||||||
|
const hexCodes: string[] = [];
|
||||||
|
const view = new DataView(buffer);
|
||||||
|
for (let i = 0; i < view.byteLength; i += 4) {
|
||||||
|
// Using getUint32 reduces the number of iterations needed (we process 4 bytes each time)
|
||||||
|
const value = view.getUint32(i);
|
||||||
|
// toString(16) will give the hex representation of the number without padding
|
||||||
|
const stringValue = value.toString(16);
|
||||||
|
// We use concatenation and slice for padding
|
||||||
|
const padding = '00000000';
|
||||||
|
const paddedValue = (padding + stringValue).slice(-padding.length);
|
||||||
|
hexCodes.push(paddedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all the hex strings into one
|
||||||
|
return hexCodes.join("");
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if crypto.subtle is available
|
||||||
|
*/
|
||||||
|
const isCryptoSubtleAvailable = (): boolean => {
|
||||||
|
return typeof crypto !== 'undefined' && crypto.subtle !== undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes sha256 Hash from String
|
||||||
|
*/
|
||||||
|
export const sha256FromString = async (stringArg: string): Promise<string> => {
|
||||||
|
// Get the string as arraybuffer.
|
||||||
|
const buffer = (new TextEncoder()).encode(stringArg);
|
||||||
|
|
||||||
|
if (isCryptoSubtleAvailable()) {
|
||||||
|
const hash = await crypto.subtle.digest("SHA-256", buffer);
|
||||||
|
const result = hex(hash);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
// Use fallback for non-HTTPS environments
|
||||||
|
return sha256Fallback(buffer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes sha256 Hash from String synchronously
|
||||||
|
* Note: In browser environment, this is still async internally but we maintain the API
|
||||||
|
*/
|
||||||
|
export const sha256FromStringSync = (stringArg: string): string => {
|
||||||
|
console.warn('sha256FromStringSync is not truly synchronous in browser environment');
|
||||||
|
throw new Error('sha256FromStringSync is not supported in browser environment. Use sha256FromString instead.');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes sha256 Hash from ArrayBuffer
|
||||||
|
*/
|
||||||
|
export const sha256FromBuffer = async (bufferArg: ArrayBuffer | Uint8Array): Promise<string> => {
|
||||||
|
if (isCryptoSubtleAvailable()) {
|
||||||
|
const hash = await crypto.subtle.digest("SHA-256", bufferArg);
|
||||||
|
const result = hex(hash);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
// Use fallback for non-HTTPS environments
|
||||||
|
const uint8Array = bufferArg instanceof Uint8Array ? bufferArg : new Uint8Array(bufferArg);
|
||||||
|
return sha256Fallback(uint8Array);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* computes sha265 Hash from Object
|
||||||
|
*/
|
||||||
|
export const sha265FromObject = async (objectArg: any): Promise<string> => {
|
||||||
|
const stringifiedObject = plugins.smartjson.stringify(objectArg);
|
||||||
|
const hashResult = await sha256FromString(stringifiedObject);
|
||||||
|
return hashResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates sha256 Hash from Stream
|
||||||
|
* Note: Not supported in browser environment
|
||||||
|
*/
|
||||||
|
export const sha256FromStream = (input: any): Promise<string> => {
|
||||||
|
throw new Error('sha256FromStream is not supported in browser environment');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates sha256 Hash from File
|
||||||
|
* Note: Not supported in browser environment
|
||||||
|
*/
|
||||||
|
export const sha256FromFile = async (filePath: string): Promise<string> => {
|
||||||
|
throw new Error('sha256FromFile is not supported in browser environment');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes MD5 Hash from String
|
||||||
|
* Note: MD5 is not natively supported by Web Crypto API
|
||||||
|
*/
|
||||||
|
export const md5FromString = async (stringToHash: string): Promise<string> => {
|
||||||
|
throw new Error('md5FromString is not supported in browser environment. Web Crypto API does not support MD5.');
|
||||||
|
};
|
8
ts_web/plugins.ts
Normal file
8
ts_web/plugins.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// pushrocks scope
|
||||||
|
import * as smartenv from '@push.rocks/smartenv';
|
||||||
|
import * as smartjson from '@push.rocks/smartjson';
|
||||||
|
|
||||||
|
export {
|
||||||
|
smartenv,
|
||||||
|
smartjson
|
||||||
|
};
|
121
ts_web/sha256.fallback.ts
Normal file
121
ts_web/sha256.fallback.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/**
|
||||||
|
* Pure JavaScript SHA256 implementation
|
||||||
|
* Used as fallback when crypto.subtle is not available (non-HTTPS contexts)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHA256 constants
|
||||||
|
*/
|
||||||
|
const K: number[] = [
|
||||||
|
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||||
|
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||||
|
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||||
|
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||||
|
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||||
|
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||||
|
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||||
|
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial hash values
|
||||||
|
*/
|
||||||
|
const H: number[] = [
|
||||||
|
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||||
|
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate right
|
||||||
|
*/
|
||||||
|
function rotr(n: number, b: number): number {
|
||||||
|
return (n >>> b) | (n << (32 - b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHA256 compression function
|
||||||
|
*/
|
||||||
|
function sha256Transform(W: number[], H: number[]): void {
|
||||||
|
let a = H[0];
|
||||||
|
let b = H[1];
|
||||||
|
let c = H[2];
|
||||||
|
let d = H[3];
|
||||||
|
let e = H[4];
|
||||||
|
let f = H[5];
|
||||||
|
let g = H[6];
|
||||||
|
let h = H[7];
|
||||||
|
|
||||||
|
for (let j = 0; j < 64; j++) {
|
||||||
|
if (j >= 16) {
|
||||||
|
const s0 = rotr(W[j - 15], 7) ^ rotr(W[j - 15], 18) ^ (W[j - 15] >>> 3);
|
||||||
|
const s1 = rotr(W[j - 2], 17) ^ rotr(W[j - 2], 19) ^ (W[j - 2] >>> 10);
|
||||||
|
W[j] = (W[j - 16] + s0 + W[j - 7] + s1) >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
||||||
|
const ch = (e & f) ^ ((~e) & g);
|
||||||
|
const temp1 = (h + S1 + ch + K[j] + W[j]) >>> 0;
|
||||||
|
|
||||||
|
const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
||||||
|
const maj = (a & b) ^ (a & c) ^ (b & c);
|
||||||
|
const temp2 = (S0 + maj) >>> 0;
|
||||||
|
|
||||||
|
h = g;
|
||||||
|
g = f;
|
||||||
|
f = e;
|
||||||
|
e = (d + temp1) >>> 0;
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b = a;
|
||||||
|
a = (temp1 + temp2) >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
H[0] = (H[0] + a) >>> 0;
|
||||||
|
H[1] = (H[1] + b) >>> 0;
|
||||||
|
H[2] = (H[2] + c) >>> 0;
|
||||||
|
H[3] = (H[3] + d) >>> 0;
|
||||||
|
H[4] = (H[4] + e) >>> 0;
|
||||||
|
H[5] = (H[5] + f) >>> 0;
|
||||||
|
H[6] = (H[6] + g) >>> 0;
|
||||||
|
H[7] = (H[7] + h) >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate SHA256 hash from bytes
|
||||||
|
*/
|
||||||
|
export function sha256Fallback(bytes: Uint8Array): string {
|
||||||
|
const H_copy = [...H];
|
||||||
|
const msgLen = bytes.length;
|
||||||
|
const msgBitLen = msgLen * 8;
|
||||||
|
|
||||||
|
// Padding
|
||||||
|
const padLen = (msgLen % 64 < 56) ? 56 - (msgLen % 64) : 120 - (msgLen % 64);
|
||||||
|
const padded = new Uint8Array(msgLen + padLen + 8);
|
||||||
|
padded.set(bytes);
|
||||||
|
padded[msgLen] = 0x80;
|
||||||
|
|
||||||
|
// Append length (64-bit big-endian)
|
||||||
|
const dataView = new DataView(padded.buffer);
|
||||||
|
dataView.setUint32(padded.length - 8, 0, false); // high 32 bits
|
||||||
|
dataView.setUint32(padded.length - 4, msgBitLen >>> 0, false); // low 32 bits
|
||||||
|
|
||||||
|
// Process blocks
|
||||||
|
for (let offset = 0; offset < padded.length; offset += 64) {
|
||||||
|
const W = new Array(64);
|
||||||
|
|
||||||
|
// Copy block into W[0..15]
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
W[i] = dataView.getUint32(offset + i * 4, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
sha256Transform(W, H_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to hex string
|
||||||
|
let hex = '';
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
hex += H_copy[i].toString(16).padStart(8, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex;
|
||||||
|
}
|
14
tsconfig.json
Normal file
14
tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"useDefineForClassFields": false,
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"verbatimModuleSyntax": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist_*/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
17
tslint.json
17
tslint.json
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": ["tslint:latest", "tslint-config-prettier"],
|
|
||||||
"rules": {
|
|
||||||
"semicolon": [true, "always"],
|
|
||||||
"no-console": false,
|
|
||||||
"ordered-imports": false,
|
|
||||||
"object-literal-sort-keys": false,
|
|
||||||
"member-ordering": {
|
|
||||||
"options":{
|
|
||||||
"order": [
|
|
||||||
"static-method"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"defaultSeverity": "warning"
|
|
||||||
}
|
|
Reference in New Issue
Block a user